在查方法的时候始终有些困扰
发觉可以按照增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)来归纳
pandas方法中的增删改查,打算近期整理下。
最近遇到一个郁闷的问题,就是列名为日期的时候,使用字符串查询列会出现KeyError。
但是你单独取df.columns
出来,所得的类型又是str,郁闷死。取出来的是str,但是你用str是无法检索的,类型不对。有空得深究解决下这个问题
初步探索:http://pandas.pydata.org/pandas-docs/stable/indexing.html
时间序列的列名,会不会是使用去除时间分隔符的字符串来获取呢?
df.loc['20130102':'20130104']
这样其实还是不行,indexing中loc方法是取行的方法……真是窘迫
和Spark的DataFrame对比的传送门:【总结】PySpark的DataFrame处理方法:增删改差
python的list结构拷贝:
c = list(a)
深度拷贝(list中嵌套的list也作为单独拷贝,而不是只引用):
import copy
f = copy.deepcopy(a)
参考链接:[Python] 正确复制列表的方法
读(Read):
df = pd.read_csv('weibo_train_data.txt', sep='\t', header=None) # 当选择列名为None的时候
df = df.rename(columns={0: 'uid', # 实际的列名为数字,而不是字符串
1: 'mid', # 使用 '0': 'uid'来改列名是改不了的
2: 'time',
3: 'forward_count',
4: 'comment_count',
5: 'like_count',
6: 'content'})
2、GroupBy
通常进行groupby操作的时候,都会进行分组。这样index就拥有层级了。如何去掉层级呢?
group_df = df.groupby(['sub_geo', 'family_desc'], as_index=False)
这样就可以了。
如果需要对日期进行按周、按月、按小时等groupby操作,可以使用pd.Grouper
(类似于SQL的window函数):
df.groupby([pd.Grouper(key="date", freq="1H"), "Location"]).agg({"Event": np.size, "Cost": np.mean})
3、如果对有层级的数据,要按照某层进行groupby怎么办呢?这样:
df.groupby(df.index.get_level_values(0)).sum()
假设数据是这样:
col1 col2
ind1 ind2
A 0 3 2
1 2 0
2 2 3
B 3 2 4
C 4 3 1
5 0 0
那么取出来get_level_values(0)
就是指ind1列,而get_level_values(1)
是指ind2列。参考
对groupby进行遍历:
for name, df_of_single_group in group_data:
pass
其中name是一个list,里面包含要groupby的列的数据,df_of_single_group则是一个pandas DataFrame
对其做类型检查则为:
from pandas.core.groupby import DataFrameGroupBy
assert isinstance(group_data, DataFrameGroupBy)
4、读取旋转后的表(转置)
df.T
增(Create):
1、新建一个dataframe:
df2 = pd.DataFrame({'A': 1.,
'B': pd.Timestamp('20130102'),
'C': pd.Series(1, index=list(range(4)), dtype='float32'),
'D': np.array([3] * 4, dtype='int32'),
'E': pd.Categorical(["test", "train", "test", "train"]),
'F': 'foo'})
或者这样:
import pandas as pd
temp = [[1, 2, 3],
[4, 5, 6, 6.5],
[7, 8, 9]]
df_p = pd.DataFrame(temp, columns=['a', 'b', 'c', 'd'])
print(df_p)
————————————————————————————
打印效果:
a b c d
0 1 2 3 NaN
1 4 5 6 6.5
2 7 8 9 NaN
2、新增一列,是原来列的组合
df['new_col'] = df['a'] + '@' + df['b'] + '@' + df['c']
3、按列归一化(需要借助sklearn包)
from sklearn import preprocessing
df = df.pivot('A', 'B', 'quantity')
x = df.values # returns a numpy array
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
assert isinstance(df, pd.DataFrame)
# 创建df,并将原来的列名封装回去
df = pd.DataFrame(x_scaled, index=df.index.values, columns=df.columns)
4、创建透视表
假设数据是这样的:
year month passengers
0 1949 January 112
1 1949 February 118
2 1949 March 132
3 1949 April 129
…… …… …… ……
11 1949 December 118
12 1950 January 115
13 1950 February 126
14 1950 March 141
我们想转换成列是month,行是year、中间是passengers的数据:
year 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959
month
January 112 115 145 171 196 204 242 284 315 340 360
February 118 126 150 180 196 188 233 277 301 318 342
March 132 141 178 193 236 235 267 317 356 362 406
April 129 135 163 181 235 227 269 313 348 348 396
May 121 125 172 183 229 234 270 318 355 363 420
June 135 149 178 218 243 264 315 374 422 435 472
July 148 170 199 230 264 302 364 413 465 491 548
August 148 170 199 242 272 293 347 405 467 505 559
September 136 158 184 209 237 259 312 355 404 404 463
October 119 133 162 191 211 229 274 306 347 359 407
November 104 114 146 172 180 203 237 271 305 310 362
December 118 140 166 194 201 229 278 306 336 337 405
那么可以这样:
import seaborn as sns
flights = sns.load_dataset("flights") # 从seaborn导入样例数据集进行演示
flights = flights.pivot("month", "year", "passengers")
如果行项目需要分更细的级别:
dfp = pd.pivot_table(dfp, index=['date', 'level_row1'], columns='col_item', values='value_col', aggfunc=np.sum)
如果不需要其分层的row,可以这么去除分层:
dfp = dfp.reset_index()
5、字符串的列改成datetime日期格式:
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
删(Delete):
1、删除一列
forecast = forecast.drop(['ds'], axis=1) # 注意这里的轴axis选择1,意思是删除列。详见这里
2、删除重复数据
df.drop_duplicates()
3、删除某些行(例:序号删除第0、1行)
df.drop(index=[0, 1])
改(或者叫做更新Update):
所有单元的操作:
1、对表中所有单元作运算(批量更改所有单元):
对DateFrame:
df.apply(lambda x: x + 1) # 所有格子数值加1
对Series类型也同理:
s.apply(lambda x: x + 1)
2、批量log、e指数运算
批量log运算:
df['y'] = np.log(df['y'])
批量e指数运算:
df['y'] = df['y'].apply(lambda x: np.e**x)
列的操作:
3、改列的内容
date_list = df['date'].tolist() # 可以通过这句获取某一列并返回list类型
…… # 经过一系列操作以后
df['date'] = ['a', 'b', 'c' …… 'z'] # 可以直接把一个list塞进dataframe里面,对该df里的列进行整体更改
4、改列名
df = df.rename(columns={'$a': 'a', '$b': 'b'})
# OR
df.rename(columns={'$a': 'a', '$b': 'b'}, inplace=True)
5、改列名方法二:
a.columns = ['ds', 'y']
6、rename对所有列名的应用lambda表达式:
df = df.rename(columns=lambda x: x.replace('$', ''))
或者
df.rename(columns=lambda x: x.replace('$', ''), inplace=True)
rename 方法可以获取函数 参考详见这里,例如:
In [11]: df.columns
Out[11]: Index([u'$a', u'$b', u'$c', u'$d', u'$e'], dtype=object)
In [12]: df.rename(columns=lambda x: x[1:], inplace=True)
In [13]: df.columns
Out[13]: Index([u'a', u'b', u'c', u'd', u'e'], dtype=object)
【可以看到,把每列的列名第一个字符之后的字符给选出来了】
7、更改df中列的数据类型:
df_p[['Q', 'R', 'S', 'T']] = df_p[['Q', 'R', 'S', 'T']].astype(np.float32) # 这么更改会保留除更改列外的其它列
df_p = df_p['Q', 'R', 'S', 'T'].astype(np.float32) # 这么更改只留下改变类型的列Q、R、S、T
update xx where操作:
8、对某列条件下的所有行的特定列的值更改操作
df_p.loc[df_p['function_name'] == test_func_name, 'state'] = 99
(当function_name这列为test…时,这些行的state列改为99)
9、更改NA的值:
df = df.fillna(value={'sub_geo': 'NA'})
order by操作(sort):
DataFrame.sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last')
参数说明:
axis: {0 or ‘index’, 1 or ‘columns’}, default 0,默认按照索引排序,即纵向排序,如果为1,则是横向排序
by: str or list of str;如果axis=0,那么by="列名";如果axis=1,那么by="行名";
ascending: 布尔型,True则升序,可以是[True,False],即第一字段升序,第二个降序
inplace: 布尔型,是否用排序后的数据框替换现有的数据框
kind: 排序方法,{‘quicksort’, ‘mergesort’, ‘heapsort’}, default ‘quicksort’。似乎不用太关心
na_position: {‘first’, ‘last’}, default ‘last’,默认缺失值排在最后面
查(Search、Retrieve):
选择某列为特定值的所有行:
df = df[df['some_col'] == "abc"]
选择null(nan)的行
df[df['some_col'].isnull()]
选择某几列为其特定值的所有行:
df = df[(df.forward_count > 0) & (df.comment_count > 0) & (df.like_count > 0)]
行选择:
n = fandango[1:3] # 索引号从0开始,选择了索引号1和2的行数据(不包括3)
o = fandango.loc[1]
p = fandango.loc[1:3] # 包含了索引号为3的那一行数据
u = fandango.loc[[1,3]] # 索引号从0开始,选择了索引号1和2的行数据(不包括3)
注意:这里loc中塞入的是索引,可以是int、str等等。当删除了某行的时候,索引号(字符串)不会自动调整,因而会出现选错行的情况。如果要严格按照顺序选取,则应当使用iloc。
fandango.iloc[-1] # 选取DataFrame最后一行,返回的是Series
fandango.iloc[-1:] # 选取DataFrame最后一行,返回的是DataFrame
列选择:
q = fandango['FILM']
r = fandango[['FILM','Metacritic']]
v = fandango[[0,1,2]]
w = fandango[list(range(5))] # 注意不能用:的方式,这样x=fandango[[0:5]]是错误的
当我们拿到一个pd.DataFrame如下的时候:
列名1 列名2 列名3
行名1 内容1 内容2 内容3
行名2 内容4 内容5 内容6
行名3 内容7 内容8 内容9
选择最左侧的index(即获取['行名1', '行名2', '行名3']
),并输出成python的list:
df.index.values # 类型为numpy.ndarray,无论是pd.DataFrame还是pd.Series都是这么选择
选择DataFrame中间的数据(即获取['内容1', …… '内容9']
不带index与header,输出格式为numpy.ndarray):
df.values # 类型为numpy.ndarray。无论是pd.DataFrame还是pd.Series都是这么选择
选择header(即获取[‘列名1’, ‘列名2’, ‘列名3’])并输出为python的list:
df.columns —————————————(类型为)—————> pd.Index
df.columns.values ——————(类型为)—————> numpy.ndarray
所有numpy.ndarray类型都可以通过tolist()
方法转变成python的list类型。
参考:Pandas之容易让人混淆的行选择和列选择、数据https://github.com/fivethirtyeight/data/tree/master/fandango
单元选择:
str(df['ds'].tail(1).iloc[0]) # 选取ds列末尾最后一个值并转化为str
索引(int行号)获取:
index_num = list(df['fruit']).index("apple") # 查找fruit列中,元素是apple的那一行的int行号
合并join操作等:
http://blog.csdn.net/ly_ysys629/article/details/73849543
附录(pd.DataFrame中可以映射的数据类型):
Data type Description
bool_ Boolean (True or False) stored as a byte
int_ Default integer type (same as C long; normally either int64 or int32)
intc Identical to C int (normally int32 or int64)
intp Integer used for indexing (same as C ssize_t; normally either int32 or int64)
int8 Byte (-128 to 127)
int16 Integer (-32768 to 32767)
int32 Integer (-2147483648 to 2147483647)
int64 Integer (-9223372036854775808 to 9223372036854775807)
uint8 Unsigned integer (0 to 255)
uint16 Unsigned integer (0 to 65535)
uint32 Unsigned integer (0 to 4294967295)
uint64 Unsigned integer (0 to 18446744073709551615)
float_ Shorthand for float64.
float16 Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
float32 Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
float64 Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
complex_ Shorthand for complex128.
complex64 Complex number, represented by two 32-bit floats (real and imaginary components)
complex128 Complex number, represented by two 64-bit floats (real and imaginary components)
高阶综合运用,筛选一维表格中按某组重复的列,剩下唯一列并生成二维表:
import pandas as pd
df = pd.DataFrame({
'a': [3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6],
'b': [1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2],
'c': ['c0', 'c1', 'c2', 'c3', 'c0', 'c1', 'c2', 'c3', 'c0', 'c1', 'c0', 'c1'],
'd': [7, 6, 7, 7, 7, 7, 7, 8, 5, 9, 5, 9]
})
print('------original df------\n', df)
df2 = pd.pivot_table(df, index=['a', 'b'], columns=['c'])
print(df2)
df4 = df[['b', 'c', 'd']].drop_duplicates(subset=['b', 'c', 'd'])
print('---------drop duplicate to count the num of diff name -----------\n', df4)
df5 = df4.groupby(['b', 'c']).count()
print('-------to find out which val diff twice in group------\n', df5)
filter_column = []
for idx_line in df5[df5['d'] > 1].index:
print(idx_line, type(idx_line), "<<<<<diff columns>>>>")
filter_column.append(('d', idx_line[1]))
print("-------Before filter---------")
print(df2)
print("-------After filter---------")
print(df2[filter_column])
输出结果:
------original df------
a b c d
0 3 1 c0 7
1 3 1 c1 6
2 3 1 c2 7
3 3 1 c3 7
4 4 1 c0 7
5 4 1 c1 7
6 4 1 c2 7
7 4 1 c3 8
8 5 2 c0 5
9 5 2 c1 9
10 6 2 c0 5
11 6 2 c1 9
d
c c0 c1 c2 c3
a b
3 1 7.0 6.0 7.0 7.0
4 1 7.0 7.0 7.0 8.0
5 2 5.0 9.0 NaN NaN
6 2 5.0 9.0 NaN NaN
---------drop duplicate to count the num of diff name -----------
b c d
0 1 c0 7
1 1 c1 6
2 1 c2 7
3 1 c3 7
5 1 c1 7
7 1 c3 8
8 2 c0 5
9 2 c1 9
-------to find out which val diff twice in group------
d
b c
1 c0 1
c1 2
c2 1
c3 2
2 c0 1
c1 1
(1, 'c1') <class 'tuple'> <<<<<diff columns>>>>
(1, 'c3') <class 'tuple'> <<<<<diff columns>>>>
-------Before filter---------
d
c c0 c1 c2 c3
a b
3 1 7.0 6.0 7.0 7.0
4 1 7.0 7.0 7.0 8.0
5 2 5.0 9.0 NaN NaN
6 2 5.0 9.0 NaN NaN
-------After filter---------
d
c c1 c3
a b
3 1 6.0 7.0
4 1 7.0 8.0
5 2 9.0 NaN
6 2 9.0 NaN
Process finished with exit code 0