一、数值计算和统计
1.数学计算方法 # 主要数学计算方法,可用于Series和DataFrame(1) df = pd.DataFrame({'key1':np.arange(10), 'key2':np.random.rand(10)*10}) print(df) print('-----') print(df.count(),'→ count统计非Na值的数量\n') print(df.min(),'→ min统计最小值\n',df['key2'].max(),'→ max统计最大值\n') print(df.quantile(q=0.75),'→ quantile统计分位数,参数q确定位置\n') print(df.sum(),'→ sum求和\n') print(df.mean(),'→ mean求平均值\n') print(df.median(),'→ median求算数中位数,50%分位数\n') print(df.std(),'\n',df.var(),'→ std,var分别求标准差,方差\n') print(df.skew(),'→ skew样本的偏度\n') print(df.kurt(),'→ kurt样本的峰度\n') df['key1_s'] = df['key1'].cumsum() df['key2_s'] = df['key2'].cumsum() print(df,'→ cumsum样本的累计和\n') df['key1_p'] = df['key1'].cumprod() df['key2_p'] = df['key2'].cumprod() print(df,'→ cumprod样本的累计积\n') print(df.cummax(),'\n',df.cummin(),'→ cummax,cummin分别求累计最大值,累计最小值\n') # 会填充key1,和key2的值
2.唯一值
# 唯一值:.unique() s = pd.Series(list('asdvasdcfgg')) # 得到一个唯一值数组 # 通过pd.Series重新变成新的Series sq = s.unique() print(s) print(sq,type(sq)) print(pd.Series(sq)) # 重新排序 sq.sort() print(sq)
3.值计数
# 值计数:.value_counts() # 得到一个新的Series,计算出不同值出现的频率 # sort参数:排序,默认为True s = pd.Series(list('asdvasdcfgg')) sc = s.value_counts(sort = False) # 也可以这样写:pd.value_counts(sc, sort = False) print(sc)
4.成员资格
# 成员资格:.isin() s = pd.Series(np.arange(10,15)) df = pd.DataFrame({'key1':list('asdcbvasd'), 'key2':np.arange(4,13)}) print(s) print(df) print('='*60,'\n') # 用[]表示 # 得到一个布尔值的Series或者Dataframe print(s.isin([5,14])) print(df.isin(['a','bc','10',8]))
二、文本数据操作
Pandas针对字符串配备的一套方法,使其易于对数组的每个元素进行操作
1.通过str访问,且自动排除丢失/ NA值
# 通过str访问,且自动排除丢失/ NA值 s = pd.Series(['A', 'b', 'C', 'bbhello', '123', np.nan, 'hj']) df = pd.DataFrame({'key1': list('abcdef'), 'key2': ['hee', 'fv', 'w', 'hija', '123', np.nan]}) print(s) print(df) print('='*60,'\n') # 直接通过.str调用字符串方法 # 可以对Series、Dataframe使用 # 自动过滤NaN值 print(s.str.count('b')) print(df['key2'].str.upper()) print('='*60,'\n') # df.columns是一个Index对象,也可使用.str # 成员资格:.isin() df.columns = df.columns.str.upper() print(df)
2.字符串常用方法
# 字符串常用方法(1) - lower,upper,len,startswith,endswith s = pd.Series(['A','b','bbhello','123',np.nan]) print(s.str.lower(),'→ lower小写\n') print(s.str.upper(),'→ upper大写\n') print(s.str.len(),'→ len字符长度\n') print(s.str.startswith('b'),'→ 判断起始是否为a\n') print(s.str.endswith('3'),'→ 判断结束是否为3\n') # 字符串常用方法(2) - strip s = pd.Series([' jack', 'jill ', ' jesse ', 'frank']) df = pd.DataFrame(np.random.randn(3, 2), columns=[' Column A ', ' Column B '], index=range(3)) print(s) print(df) print('-----') print(s.str.strip()) # 去除字符串中的空格 print(s.str.lstrip()) # 去除字符串中的左空格 print(s.str.rstrip()) # 去除字符串中的右空格 # 这里去掉了columns的前后空格,但没有去掉中间空格 df.columns = df.columns.str.strip() print(df) # 字符串常用方法(3) - replace df = pd.DataFrame(np.random.randn(3, 2), columns=[' Column A ', ' Column B '], index=range(3)) df.columns = df.columns.str.replace(' ','-') print(df) # n:替换个数 df.columns = df.columns.str.replace('-','hehe',n=1) print(df) # 字符串常用方法(4) - split、rsplit # 类似字符串的split s = pd.Series(['a,b,c','1,2,3',['a,,,c'],np.nan]) print(s.str.split(',')) print('-----') # 直接索引得到一个list print(s.str.split(',')[0]) print('-----') # 可以使用get或[]符号访问拆分列表中的元素 print(s.str.split(',').str[0]) print(s.str.split(',').str.get(1)) print('-----') # 可以使用expand可以轻松扩展此操作以返回DataFrame # n参数限制分割数 # rsplit类似于split,反向工作,即从字符串的末尾到字符串的开头 print(s.str.split(',', expand=True)) print(s.str.split(',', expand=True, n = 1)) print(s.str.rsplit(',', expand=True, n = 1)) print('-----') # Dataframe使用split df = pd.DataFrame({'key1':['a,b,c','1,2,3',[':,., ']], 'key2':['a-b-c','1-2-3',[':-.- ']]}) print(df['key2'].str.split('-')) # 字符串索引 s = pd.Series(['A','b','C','bbhello','123',np.nan,'hj']) df = pd.DataFrame({'key1':list('abcdef'), 'key2':['hee','fv','w','hija','123',np.nan]}) print(s.str[0]) # 取第一个字符串 print(s.str[:2]) # 取前两个字符串 print(df['key2'].str[0]) # str之后和字符串本身索引方式相同
三、合并merge、join
Pandas具有全功能的,高性能内存中连接操作,与SQL等关系数据库非常相似
1.merge合并
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=('_x', '_y'), copy=True, indicator=False) 1.merge合并 → 类似excel的vlookup df1 = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'], 'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3']}) df2 = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}) df3 = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'], 'key2': ['K0', 'K1', 'K0', 'K1'], 'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3']}) df4 = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'], 'key2': ['K0', 'K0', 'K0', 'K0'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}) # left:第一个df # right:第二个df # on:参考键 print(pd.merge(df1, df2, on='key')) # 多个链接键 print(pd.merge(df3, df4, on=['key1','key2'])) 2.参数how → 合并方式 # inner:默认,取交集 print(pd.merge(df3, df4,on=['key1','key2'], how = 'inner')) print('------') # outer:取并集,数据缺失范围NaN print(pd.merge(df3, df4, on=['key1','key2'], how = 'outer')) # left:按照df3为参考合并,数据缺失范围NaN print(pd.merge(df3, df4, on=['key1','key2'], how = 'left')) # right:按照df4为参考合并,数据缺失范围NaN print(pd.merge(df3, df4, on=['key1','key2'], how = 'right')) 3.参数 left_on, right_on, left_index, right_index → 当键不为一个列时,可以单独设置左键与右键 # df1以‘lkey’为键,df2以‘rkey’为键 df1 = pd.DataFrame({'lkey':list('bbacaab'), 'data1':range(7)}) df2 = pd.DataFrame({'rkey':list('abd'), 'date2':range(3)}) print(pd.merge(df1, df2, left_on='lkey', right_on='rkey')) # df1以‘key’为键,df2以index为键 # left_index:为True时,第一个df以index为键,默认False # right_index:为True时,第二个df以index为键,默认False # 所以left_on, right_on, left_index, right_index可以相互组合: # left_on + right_on, left_on + right_index, left_index + right_on, left_index + right_index df1 = pd.DataFrame({'key':list('abcdfeg'), 'data1':range(7)}) df2 = pd.DataFrame({'date2':range(100,105)}, index = list('abcde')) print(pd.merge(df1, df2, left_on='key', right_index=True)) 4.参数 sort df1 = pd.DataFrame({'key':list('bbacaab'), 'data1':[1,3,2,4,5,9,7]}) df2 = pd.DataFrame({'key':list('abd'), 'date2':[11,2,33]}) x1 = pd.merge(df1,df2, on = 'key', how = 'outer') # sort:按照字典顺序通过 连接键 对结果DataFrame进行排序。默认为False,设置为False会大幅提高性能 x2 = pd.merge(df1,df2, on = 'key', sort=True, how = 'outer') print(x1) print(x2) print('------') # 也可直接用Dataframe的排序方法:sort_values,sort_index print(x2.sort_values('data1'))
2.join链接
# pd.join() → 直接通过索引链接 left = pd.DataFrame({'A': ['A0', 'A1', 'A2'], 'B': ['B0', 'B1', 'B2']}, index=['K0', 'K1', 'K2']) right = pd.DataFrame({'C': ['C0', 'C2', 'C3'], 'D': ['D0', 'D2', 'D3']}, index=['K0', 'K2', 'K3']) # 等价于:pd.merge(left, right, left_index=True, right_index=True, how='outer') print(left) print(right) print(left.join(right)) print(left.join(right, how='outer')) df1 = pd.DataFrame({'key':list('bbacaab'), 'data1':[1,3,2,4,5,9,7]}) df2 = pd.DataFrame({'key':list('abd'), 'date2':[11,2,33]}) print(df1) print(df2) print(pd.merge(df1, df2, left_index=True, right_index=True, suffixes=('_1', '_2'))) print(df1.join(df2['date2'])) print('-----') # suffixes=('_x', '_y')默认 left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'key': ['K0', 'K1', 'K0', 'K1']}) right = pd.DataFrame({'C': ['C0', 'C1'], 'D': ['D0', 'D1']}, index=['K0', 'K1']) # 等价于pd.merge(left, right, left_on='key', right_index=True, how='left', sort=False); # left的‘key’和right的index print(left) print(right) print(left.join(right, on = 'key'))
四、连接与修补
1. 连接:concat s1 = pd.Series([1,2,3]) s2 = pd.Series([2,3,4]) s3 = pd.Series([1,2,3],index = ['a','c','h']) s4 = pd.Series([2,3,4],index = ['b','e','d']) print(pd.concat([s1,s2])) # 默认axis=0,行+行 print(pd.concat([s3,s4]).sort_index()) # axis=1,列+列,成为一个Dataframe print(pd.concat([s3,s4], axis=1)) 2.连接方式:join,join_axes s5 = pd.Series([1,2,3],index = ['a','b','c']) s6 = pd.Series([2,3,4],index = ['b','c','d']) print(pd.concat([s5,s6], axis= 1)) # join:{'inner','outer'},默认为“outer”。如何处理其他轴上的索引。outer为联合和inner为交集。 # join_axes:指定联合的index print(pd.concat([s5,s6], axis= 1, join='inner')) print(pd.concat([s5,s6], axis= 1, join_axes=[['a','b','d']])) 3.覆盖列名 # keys:序列,默认值无。使用传递的键作为最外层构建层次索引 sre = pd.concat([s5,s6], keys = ['one','two']) print(sre,type(sre)) print(sre.index) # axis = 1, 覆盖列名 sre = pd.concat([s5,s6], axis=1, keys = ['one','two']) print(sre,type(sre)) 4.修补 pd.combine_first() # 根据index,df1的空值被df2替代 # 如果df2的index多于df1,则更新到df1上,比如index=['a',1] df1 = pd.DataFrame([[np.nan, 3., 5.], [-4.6, np.nan, np.nan],[np.nan, 7., np.nan]]) df2 = pd.DataFrame([[-42.6, np.nan, -8.2], [-5., 1.6, 4]],index=[1, 2]) print(df1) print(df2) print(df1.combine_first(df2)) # update,直接df2覆盖df1,相同index位置 df1.update(df2) print(df1)
五、去重及替换
1.去重 .duplicated # 判断是否重复 # 通过布尔判断,得到不重复的值 s = pd.Series([1,1,1,1,2,2,2,3,4,5,5,5,5]) print(s.duplicated()) print(s[s.duplicated() == False]) # drop.duplicates移除重复 # inplace参数:是否替换原值,默认False s_re = s.drop_duplicates() print(s_re) # Dataframe中使用duplicated df = pd.DataFrame({'key1':['a','a',3,4,5], 'key2':['a','a','b','b','c']}) print(df.duplicated()) print(df['key2'].duplicated()) 2.替换 .replace # 可一次性替换一个值或多个值 # 可传入列表或字典 s = pd.Series(list('ascaazsd')) print(s.replace('a', np.nan)) print(s.replace(['a','s'] ,np.nan)) print(s.replace({'a':'hello world!','s':123}))
六、数据分组
分组统计 - groupby功能 ① 根据某些条件将数据拆分成组 ② 对每个组独立应用函数 ③ 将结果合并到一个数据结构中 Dataframe在行(axis=0)或列(axis=1)上进行分组,将一个函数应用到各个分组并产生一个新值,然后函数执行结果被合并到最终的结果对象中。 df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)
1.通用分组
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo'], 'B' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'C' : np.random.randn(8), 'D' : np.random.randn(8)}) print(df) print('='*60,'\n') # 直接分组得到一个groupby对象,是一个中间数据,没有进行计算 print(df.groupby('A'), type(df.groupby('A'))) print('='*60,'\n') # 通过分组后的计算,得到一个新的dataframe # 默认axis = 0,以行来分组 # 可单个或多个([])列分组 a = df.groupby('A').mean(numeric_only=True) b = df.groupby(['A','B']).mean() c = df.groupby(['A'])['D'].mean() # 以A分组,算D的平均值 print(a,type(a),'\n',a.columns) print(b,type(b),'\n',b.columns) print(c,type(c))
2.可迭代对象分组
# 分组 - 可迭代对象 df = pd.DataFrame({'X' : ['A', 'B', 'A', 'B'], 'Y' : [1, 4, 3, 2]}) print(df) print(df.groupby('X'), type(df.groupby('X'))) # n是组名,g是分组后的Dataframe print(list(df.groupby('X')), '→ 可迭代对象,直接生成list\n') print(list(df.groupby('X'))[0], '→ 以元祖形式显示\n') for n,g in df.groupby('X'): print(n) print(g) print('###') # .get_group()提取分组后的组 print(df.groupby(['X']).get_group('A'),'\n') print(df.groupby(['X']).get_group('B'),'\n') # .groups:将分组后的groups转为dict # 可以字典索引方法来查看groups里的元素 grouped = df.groupby(['X']) print(grouped.groups) print(grouped.groups['A']) # 也可写:df.groupby('X').groups['A'] # .size():查看分组后的长度 sz = grouped.size() print(sz,type(sz)) print('-----') # 按照两个列进行分组 df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo'], 'B' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'C' : np.random.randn(8), 'D' : np.random.randn(8)}) grouped = df.groupby(['A','B']).groups print(df) print(grouped) print(grouped[('foo', 'three')])
3.其他轴分组
df = pd.DataFrame({'data1':np.random.rand(2), 'data2':np.random.rand(2), 'key1':['a','b'], 'key2':['one','two']}) # 按照值类型分列 print(df) print(df.dtypes) print('-----') for n,p in df.groupby(df.dtypes, axis=1): print(n) print(p) print('##')
4.通过字典或者Series分组
# 通过字典或者Series分组 df = pd.DataFrame(np.arange(16).reshape(4,4), columns = ['a','b','c','d']) print(df) # mapping中,a、b列对应的为one,c、d列对应的为two,以字典来分组 mapping = {'a':'one','b':'one','c':'two','d':'two','e':'three'} by_column = df.groupby(mapping, axis = 1) print(by_column.sum()) # s中,index中a、b对应的为one,c、d对应的为two,以Series来分组 s = pd.Series(mapping) print(s,'\n') print(s.groupby(s).count())
5.通过函数分组
df = pd.DataFrame(np.arange(16).reshape(4,4), columns = ['a','b','c','d'], index = ['abc','bcd','aa','b']) print(df,'\n') # 按照字母长度分组 print(df.groupby(len).sum())
6.分组计算函数方法
# 分组计算函数方法 s = pd.Series([1, 2, 3, 10, 20, 30], index = [1, 2, 3, 1, 2, 3]) grouped = s.groupby(level=0) # 唯一索引用.groupby(level=0),将同一个index的分为一组 print(grouped) print(grouped.first(),'→ first:非NaN的第一个值\n') print(grouped.last(),'→ last:非NaN的最后一个值\n') print(grouped.sum(),'→ sum:非NaN的和\n') print(grouped.mean(),'→ mean:非NaN的平均值\n') print(grouped.median(),'→ median:非NaN的算术中位数\n') print(grouped.count(),'→ count:非NaN的值\n') print(grouped.min(),'→ min、max:非NaN的最小值、最大值\n') print(grouped.std(),'→ std,var:非NaN的标准差和方差\n') print(grouped.prod(),'→ prod:非NaN的积\n')
七、多函数计算
df = pd.DataFrame({'a':[1,1,2,2], 'b':np.random.rand(4), 'c':np.random.rand(4), 'd':np.random.rand(4),}) print(df) # 函数写法可以用str,或者np.方法 # 可以通过list,dict传入,当用dict时,key名为columns print(df.groupby('a').agg(['mean',np.sum])) print(df.groupby('a')['b'].agg([('B',np.mean), ('C',np.sum)]))
八、分组转换及一般性“拆分-应用-合并”
1.数据分组转换
# 数据分组转换,transform df = pd.DataFrame({'data1':np.random.rand(5), 'data2':np.random.rand(5), 'key1':list('aabba'), 'key2':['one','two','one','two','one']}) k_mean = df.groupby('key1').mean(numeric_only=True) print(df) print(k_mean) # 通过分组、合并,得到一个包含均值的Dataframe print(pd.merge(df,k_mean,left_on='key1',right_index=True).add_prefix('mean_')) # .add_prefix('mean_'):添加前缀 # data1、data2每个位置元素取对应分组列的均值 # 字符串不能进行计算 print(df.groupby('key2').mean(numeric_only=True)) # 按照key2分组求均值 #print(df.groupby('key2').transform(np.mean))
2.一般化Groupby方法
# 一般化Groupby方法:apply df = pd.DataFrame({'data1': np.random.rand(5), 'data2': np.random.rand(5), 'key1': list('aabba'), 'key2': ['one', 'two', 'one', 'two', 'one']}) # apply直接运行其中的函数 # 这里为匿名函数,直接描述分组后的统计量 print(df.groupby('key1').apply(lambda x: x.describe())) def f_df1(d, n): return (d.sort_index()[:n]) def f_df2(d, k1): return (d[k1]) # f_df1函数:返回排序后的前n行数据 # f_df2函数:返回分组后表的k1列,结果为Series,层次化索引 # 直接运行f_df函数 # 参数直接写在后面,也可以为.apply(f_df,n = 2)) print(df.groupby('key1').apply(f_df1, 2), '\n') print(df.groupby('key1').apply(f_df2, 'data2')) print(type(df.groupby('key1').apply(f_df2, 'data2')))
九、透视表及交叉表
1.透视表
# 透视表:pivot_table # pd.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All') date = ['2017-5-1','2017-5-2','2017-5-3']*3 rng = pd.to_datetime(date) df = pd.DataFrame({'date':rng, 'key':list('abcdabcda'), 'values':np.random.rand(9)*10}) print(df) # data:DataFrame对象 # values:要聚合的列或列的列表 # index:数据透视表的index,从原数据的列中筛选 # columns:数据透视表的columns,从原数据的列中筛选 # aggfunc:用于聚合的函数,默认为numpy.mean,支持numpy计算方法 print(pd.pivot_table(df, values = 'values', index = 'date', columns = 'key', aggfunc=np.sum)) # 也可以写 aggfunc='sum' # 这里就分别以date、key共同做数据透视,值为values:统计不同(date,key)情况下values的平均值 # aggfunc=len(或者count):计数 print(pd.pivot_table(df, values = 'values', index = ['date','key'], aggfunc=len))
2.交叉表
# 交叉表:crosstab # 默认情况下,crosstab计算因子的频率表,比如用于str的数据透视分析 # pd.crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, dropna=True, normalize=False) df = pd.DataFrame({'A': [1, 2, 2, 2, 2], 'B': [3, 3, 4, 4, 4], 'C': [1, 1, np.nan, 1, 1]}) # 如果crosstab只接收两个Series,它将提供一个频率表。 # 用A的唯一值,统计B唯一值的出现次数 print(pd.crosstab(df['A'],df['B'])) # normalize:默认False,将所有值除以值的总和进行归一化 → 为True时候显示百分比 print(pd.crosstab(df['A'],df['B'],normalize=True)) # values:可选,根据因子聚合的值数组 # aggfunc:可选,如果未传递values数组,则计算频率表,如果传递数组,则按照指定计算 # 这里相当于以A和B界定分组,计算出每组中第三个系列C的值 print(pd.crosstab(df['A'],df['B'],values=df['C'],aggfunc=np.sum)) # margins:布尔值,默认值False,添加行/列边距(小计) print(pd.crosstab(df['A'],df['B'],values=df['C'],aggfunc=np.sum, margins=True))
十、数据读取
1.读取普通分隔数据
import os os.chdir('C:/Users/Hjx/Desktop/') # delimiter:用于拆分的字符,也可以用sep:sep = ',' # header:用做列名的序号,默认为0(第一行) # index_col:指定某列为行索引,否则自动索引0, 1, ..... # read_table主要用于读取简单的数据,txt/csv data1 = pd.read_table('data1.txt', delimiter=',',header = 0, index_col=1) print(data1)
2.读取csv数据
# 读取csv数据:read_csv # 先熟悉一下excel怎么导出csv # engine:使用的分析引擎。可以选择C或者是python。C引擎快但是Python引擎功能更加完备。 # encoding:指定字符集类型,即编码,通常指定为'utf-8' # 大多数情况先将excel导出csv,再读取 data2 = pd.read_csv('data2.csv',engine = 'python') print(data2.head())
3.读取excel数据
# 读取excel数据:read_excel # io :文件路径。 # sheetname:返回多表使用sheetname=[0,1],若sheetname=None是返回全表 → ① int/string 返回的是dataframe ②而none和list返回的是dict # header:指定列名行,默认0,即取第一行 # index_col:指定列为索引列,也可以使用u”strings” data3 = pd.read_excel('地市级党委书记数据库(2000-10).xlsx',sheetname='中国人民共和国地市级党委书记数据库(2000-10)',header=0) print(data3)
十一、数据导出