04. Pandas 3| 数值计算与统计、合并连接去重分组透视表文件读取
1.数值计算和统计基础
常用数学、统计方法
数值计算和统计基础
基本参数:axis、skipna
df.mean(axis=1,skipna=False) -->> axis=1是按行来进行统计; 默认按列统计(axis默认为0,可不写); skipna=False是不忽略,显示NaN,默认为True,即忽略NaN.
>>> import numpy as np >>> import pandas as pd >>> df = pd.DataFrame({'key1':[4,5,3,np.nan,2], # np.nan :空值 ... 'key2':[1,2,np.nan,4,5], ... 'key3':[1,2,3,'j','k']}, #字符串 ... index = ['a','b','c','d','e']) >>> print(df) key1 key2 key3 a 4.0 1.0 1 b 5.0 2.0 2 c 3.0 NaN 3 d NaN 4.0 j e 2.0 5.0 k >>> print(df['key1'].dtype, df['key2'].dtype, df['key3'].dtype) float64 float64 object (object是python的对象)
>>> print(df.mean(),type(df.mean)) #.mean()计算均值(默认按列),只统计数字列 ,key3为object对象不统计。
key1 3.5
key2 3.0
dtype: float64 <class 'pandas.core.series.Series'>
>>>
>>> print('单独统计一列:',df['key2'].mean()) # .mean()计算均值 # 可以通过索引单独统计一列; 单独统计一列: 3.0 >>> >>> m2 = df.mean(axis=1) # 只统计数字列 #axis参数:默认为0,以列来计算, axis=1,以行来计算,这里就按照行来汇总了,也是只统计数字那行 >>> print(m2) a 2.5 b 3.5 c 3.0 d 4.0 e 3.5 dtype: float64 >>>
>>> print(df.mean(axis=1, skipna=False)) #以行来算; skipna参数是是否忽略NaN,默认True忽略结果同上;False是有NaN的行,就直接显示NaN了不忽略它。
a 2.5
b 3.5
c NaN
d NaN
e 3.5
dtype: float64
>>>
>>> m3 = df.mean(skipna=False) #按列来算 >>> print(m3) key1 NaN key2 NaN dtype: float64 >>>
主要数学计算方法,可用于Series和DataFrame(1)
.count( )统计非NaN值的数量、.min()、.max()、 .quantile(q=0.5)统计分位数、 .sum()求和、 .mean()平均值 、.median()中位数 、.std() 标准差、.var()方差
>>> df = pd.DataFrame({'key1':np.arange(10), ... 'key2':np.random.rand(10)*10}) >>> print(df) key1 key2 0 0 7.556713 1 1 8.650398 2 2 4.692490 3 3 0.275988 4 4 2.710686 5 5 5.130423 6 6 3.638846 7 7 2.989476 8 8 7.105496 9 9 0.907657 >>> print(df.count(),'→ count统计非Na值的数量\n') key1 10 key2 10 dtype: int64 → count统计非Na值的数量 >>> print(df.min(),'→ min统计最小值\n',df['key2'].max(),'→ max统计最大值\n') key1 0.000000 key2 0.275988 dtype: float64 → min统计最小值 8.650397903041455 → max统计最大值 >>> print(df.quantile(q=0.75),'→ quantile统计分位数,参数q确定位置\n') #q=0.75,分位数就是总共数的3/4位置的那个数 key1 6.750000 key2 6.611727 Name: 0.75, dtype: float64 → quantile统计分位数,参数q确定位置 >>> print(df.sum(),'→ sum求和\n') key1 45.000000 key2 43.658172 dtype: float64 → sum求和 >>> print(df.mean(),'→ mean求平均值\n') key1 4.500000 key2 4.365817 dtype: float64 → mean求平均值 >>> print(df.median(),'→ median求算数中位数,50%分位数\n') key1 4.500000 key2 4.165668 dtype: float64 → median求算数中位数,50%分位数 >>> print(df.std(),'\n',df.var(),'→ std,var分别求标准差,方差\n') key1 3.027650 key2 2.800485 dtype: float64 key1 9.166667 key2 7.842718 dtype: float64 → std,var分别求标准差,方差 >>> print(df.skew(),'→ skew样本的偏度\n') #偏度和峰度是用来进行一致性检验的。 key1 0.000000 key2 0.094214 dtype: float64 → skew样本的偏度 >>> print(df.kurt(),'→ kurt样本的峰度\n') key1 -1.200000 key2 -1.033864 dtype: float64 → kurt样本的峰度 >>>
主要数学计算方法,可用于Series和DataFrame(2)
df.cumsum()累积求和、 df.cumprod()累计求积、 df.cummax()累计最大值,出现最大值了就一直是那个最大值了、 cummin()累计最小值
>>> df['key1_s'] = df['key1'].cumsum() #样本的累计和,默认列。下面这4个赋值,给df添加了4个字段。 >>> df['key2_s'] = df['key2'].cumsum() >>> print(df,'→ cumsum样本的累计和\n') key1 key2 key1_s key2_s 0 0 7.556713 0 7.556713 1 1 8.650398 1 16.207111 2 2 4.692490 3 20.899601 3 3 0.275988 6 21.175589 4 4 2.710686 10 23.886275 5 5 5.130423 15 29.016698 6 6 3.638846 21 32.655544 7 7 2.989476 28 35.645019 8 8 7.105496 36 42.750515 9 9 0.907657 45 43.658172 → cumsum样本的累计和 >>> df['key1_p'] = df['key1'].cumprod() #样本的累计积,默认列 >>> df['key2_p'] = df['key2'].cumprod() >>> print(df,'→ cumprod样本的累计积\n') key1 key2 key1_s key2_s key1_p key2_p 0 0 7.556713 0 7.556713 0 7.556713 1 1 8.650398 1 16.207111 0 65.368572 2 2 4.692490 3 20.899601 0 306.741386 3 3 0.275988 6 21.175589 0 84.656944 4 4 2.710686 10 23.886275 0 229.478404 5 5 5.130423 15 29.016698 0 1177.321217 6 6 3.638846 21 32.655544 0 4284.090351 7 7 2.989476 28 35.645019 0 12807.184945 8 8 7.105496 36 42.750515 0 91001.397399 9 9 0.907657 45 43.658172 0 82598.051142 → cumprod样本的累计积 >>> print(df.cummax(),'\n',df.cummin(),'→ cummax,cummin分别求累计最大值,累计最小值\n') #累计最大值和最小值会直接填充之前的key1、key2 key1 key2 key1_s key2_s key1_p key2_p 0 0.0 7.556713 0.0 7.556713 0.0 7.556713 1 1.0 8.650398 1.0 16.207111 0.0 65.368572 2 2.0 8.650398 3.0 20.899601 0.0 306.741386 3 3.0 8.650398 6.0 21.175589 0.0 306.741386 4 4.0 8.650398 10.0 23.886275 0.0 306.741386 5 5.0 8.650398 15.0 29.016698 0.0 1177.321217 6 6.0 8.650398 21.0 32.655544 0.0 4284.090351 7 7.0 8.650398 28.0 35.645019 0.0 12807.184945 8 8.0 8.650398 36.0 42.750515 0.0 91001.397399 9 9.0 8.650398 45.0 43.658172 0.0 91001.397399 key1 key2 key1_s key2_s key1_p key2_p 0 0.0 7.556713 0.0 7.556713 0.0 7.556713 1 0.0 7.556713 0.0 7.556713 0.0 7.556713 2 0.0 4.692490 0.0 7.556713 0.0 7.556713 3 0.0 0.275988 0.0 7.556713 0.0 7.556713 #出现最小值了就一直累计那个最小值 4 0.0 0.275988 0.0 7.556713 0.0 7.556713 5 0.0 0.275988 0.0 7.556713 0.0 7.556713 6 0.0 0.275988 0.0 7.556713 0.0 7.556713 7 0.0 0.275988 0.0 7.556713 0.0 7.556713 8 0.0 0.275988 0.0 7.556713 0.0 7.556713 9 0.0 0.275988 0.0 7.556713 0.0 7.556713 → cummax,cummin分别求累计最大值,累计最小值 >>>
唯一值:.unique( ) 去掉重复的值
s.unique()
>>> s = pd.Series(list('asdvasdcfgg')) >>> sq = s.unique() #得到一个只有唯一数值的数组,没有重复值了 >>> print(s) 0 a 1 s 2 d 3 v 4 a 5 s 6 d 7 c 8 f 9 g 10 g dtype: object >>> print(sq,type(sq)) ['a' 's' 'd' 'v' 'c' 'f' 'g'] <class 'numpy.ndarray'> >>> print(pd.Series(sq)) # 通过pd.Series重新变成新的Series 0 a 1 s 2 d 3 v 4 c 5 f 6 g dtype: object >>> sq.sort() >>> print(sq) ['a' 'c' 'd' 'f' 'g' 's' 'v'] >>>
值计数:.value_counts() 计算不同值出现的频率
s.value_counts(sort = False) # 也可以这样写:pd.value_counts(sc, sort = False), sort=False是不排序,sort默认为True降序。
>>> sc = s.value_counts(sort = False) # 也可以这样写:pd.value_counts(sc, sort = False) >>> print(sc) # 得到一个新的Series,计算出不同值出现的频率; # sort参数:排序,默认为True降序,False是不排序。 s 2 d 2 v 1 f 1 c 1 g 2 a 2 dtype: int64 >>>
成员资格:.isin() 判断值是否在里边
s.isin( [ 3, 12 ] ) 数值3和12是否在里边
>>> s = pd.Series(np.arange(10,15)) >>> df = pd.DataFrame({'key1':list('asdcbvasd'), ... 'key2':np.arange(4,13)}) >>> print(s) 0 10 1 11 2 12 3 13 4 14 dtype: int32 >>> print(df) key1 key2 0 a 4 1 s 5 2 d 6 3 c 7 4 b 8 5 v 9 6 a 10 7 s 11 8 d 12 >>> print('-----') ----- >>> >>> print(s.isin([5,14])) 0 False 1 False 2 False 3 False 4 True dtype: bool >>> print(df.isin(['a','bc','10',8])) key1 key2 0 True False 1 False False 2 False False 3 False False 4 False True 5 False False 6 True False 7 False False 8 False False >>>
2.文本数据
Pandas针对字符串配备的一套方法,使其易于对数组的每个元素进行操作。
2.1 通过str访问,且自动排除丢失/ NA值
.str调用字符串方法 s.str.count('b') .str.upper() df.columns.str.upper()
>>> 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) 0 A 1 b 2 C 3 bbhello 4 123 5 NaN 6 hj dtype: object >>> print(df) key1 key2 0 a hee 1 b fv 2 c w 3 d hija 4 e 123 5 f NaN >>> >>> print(s.str.count('b')) # 直接通过.str调用字符串方法 # 可以对Series、Dataframe使用 # 自动过滤NaN值 0 0.0 1 1.0 2 0.0 3 2.0 4 0.0 5 NaN 6 0.0 dtype: float64 >>> print(df['key2'].str.upper()) 0 HEE 1 FV 2 W 3 HIJA 4 123 5 NaN Name: key2, dtype: object >>> >>> df.columns = df.columns.str.upper() # df.columns是一个Index对象,也可使用.str >>> print(df) KEY1 KEY2 0 a hee 1 b fv 2 c w 3 d hija 4 e 123 5 f NaN >>>
2.2 字符串常用方法 - lower,upper,len,startswith,endswith,strip,replace,split
f['key2'].str.upper() .str.len() .str.startswith('b') .str.endswith('3') .str.strip()去除字符串中空格
df.columns.str.replace(' ', '-') .str.split(',')) .str.split(',').str.get(1) .str.split(',',expand=True)
s.str.split(',',expand=True,n=1) expand是将Series变为DataFrame,n=1是限制分割多少列
########字符串常用方法(一)
>>> 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) 0 A 1 b 2 C 3 bbhello 4 123 5 NaN 6 hj dtype: object >>> print(df) key1 key2 0 a hee 1 b fv 2 c w 3 d hija 4 e 123 5 f NaN >>> >>> print(s.str.count('b')) 0 0.0 1 1.0 2 0.0 3 2.0 4 0.0 5 NaN 6 0.0 dtype: float64 >>> print(df['key2'].str.upper()) 0 HEE 1 FV 2 W 3 HIJA 4 123 5 NaN Name: key2, dtype: object >>> >>> df.columns = df.columns.str.upper() >>> print(df) KEY1 KEY2 0 a hee 1 b fv 2 c w 3 d hija 4 e 123 5 f NaN >>> >>> >>> >>> >>> >>> s = pd.Series(['A','b','bbhello','123',np.nan]) >>> print(s.str.lower(),'→ lower小写\n') 0 a 1 b 2 bbhello 3 123 4 NaN dtype: object → lower小写 >>> print(s.str.upper(),'→ lower大写\n') 0 A 1 B 2 BBHELLO 3 123 4 NaN dtype: object → lower大写 >>> print(s.str.len(),'→ len字符长度\n') 0 1.0 1 1.0 2 7.0 3 3.0 4 NaN dtype: float64 → len字符长度 >>> print(s.str.startswith('b'),'→ 判断起始是否为a\n') 0 False 1 True 2 True 3 False 4 NaN dtype: object → 判断起始是否为a >>> print(s.str.endswith('3'),'→ 判断结束是否为3\n') 0 False 1 False 2 False 3 True 4 NaN dtype: object → 判断结束是否为3 >>> >>> >>>字符串常用方法(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) 0 jack 1 jill 2 jesse 3 frank dtype: object >>> print(df) Column A Column B 0 1.134152 1.030622 1 -0.509581 -0.102576 2 1.033234 -1.170396 >>> >>> print(s.str.strip()) # 去除字符串中的空格 0 jack 1 jill 2 jesse 3 frank dtype: object >>> print(s.str.lstrip()) # 去除字符串中的左空格 0 jack 1 jill 2 jesse 3 frank dtype: object >>> print(s.str.rstrip()) # 去除字符串中的右空格 0 jack 1 jill 2 jesse 3 frank dtype: object >>> df.columns = df.columns.str.strip() # 这里去掉了columns的前后空格,但没有去掉中间空格 >>> print(df) Column A Column B 0 1.134152 1.030622 1 -0.509581 -0.102576 2 1.033234 -1.170396 >>> >>> >>># 字符串常用方法(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) -Column-A- -Column-B- 0 -0.721763 0.899423 1 1.129852 0.893515 2 -1.715414 -1.465260 >>> >>> df.columns = df.columns.str.replace('-','hehe',n=1) >>> print(df) heheColumn-A- heheColumn-B- 0 -0.721763 0.899423 1 1.129852 0.893515 2 -1.715414 -1.465260 >>> >>> >>># 字符串常用方法(4) - split、rsplit >>> s = pd.Series(['a,b,c','1,2,3',['a,,,c'],np.nan]) >>> print(s.str.split(',')) # 类似字符串的split 0 [a, b, c] 1 [1, 2, 3] 2 NaN 3 NaN dtype: object >>> print(s.str.split(',')[0]) ## 直接索引得到一个list ['a', 'b', 'c'] >>> >>> print(s.str.split(',').str[0]) 0 a 1 1 2 NaN 3 NaN dtype: object >>> print(s.str.split(',').str.get(1)) # 可以使用get或[]符号访问拆分列表中的元素 0 b 1 2 2 NaN 3 NaN dtype: object >>> >>> print(s.str.split(',',expand=True)) # 可以使用expand可以轻松扩展此操作以返回DataFrame;expand默认为False 0 1 2 0 a b c 1 1 2 3 2 NaN NaN NaN 3 NaN NaN NaN >>> print(s.str.split(',',expand=True,n=1)) # n参数限制分割数 0 1 0 a b,c 1 1 2,3 2 NaN NaN 3 NaN NaN >>> print(s.str.rsplit(',',expand=True,n=1)) # rsplit类似于split,反向工作,即从字符串的末尾到字符串的开头 0 1 0 a,b c 1 1,2 3 2 NaN NaN 3 NaN NaN >>>
>>> df = pd.DataFrame({'key1':['a,b,c','1,2,3',[':,., ']], ... 'key2':['a-b-c','1-2-3',[':-.- ']]}) >>> print(df['key2'].str.split('-')) # Dataframe使用split 0 [a, b, c] 1 [1, 2, 3] 2 NaN Name: key2, dtype: object >>>
字符串索引
s.str[ 0 ] .str[ :2 ]
>>> 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) 0 A 1 b 2 C 3 bbhello 4 123 5 NaN 6 hj dtype: object >>> print(df) key1 key2 0 a hee 1 b fv 2 c w 3 d hija 4 e 123 5 f NaN >>> print(s.str[0]) # 取第一个字符串 0 A 1 b 2 C 3 b 4 1 5 NaN 6 h dtype: object >>> print(s.str[:2]) # 取前两个字符串 0 A 1 b 2 C 3 bb 4 12 5 NaN 6 hj dtype: object >>> print(df['key2'].str[0]) # str之后和字符串本身索引方式相同 0 h 1 f 2 w 3 h 4 1 5 NaN Name: key2, dtype: object >>>
3.合并 merge、join
Pandas具有全功能的,高性能内存中连接操作,与SQL等关系数据库非常相似
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)
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']}) >>> print(df1) key A B 0 K0 A0 B0 1 K1 A1 B1 2 K2 A2 B2 3 K3 A3 B3 >>> print(df2) key C D 0 K0 C0 D0 1 K1 C1 D1 2 K2 C2 D2 3 K3 C3 D3 >>> >>> print(pd.merge(df1, df2, on='key')) # left:第一个df; #right:第二个df #on:参考键; key A B C D 0 K0 A0 B0 C0 D0 1 K1 A1 B1 C1 D1 2 K2 A2 B2 C2 D2 3 K3 A3 B3 C3 D3 >>> print(df3) key1 key2 A B 0 K0 K0 A0 B0 1 K0 K1 A1 B1 2 K1 K0 A2 B2 3 K2 K1 A3 B3 >>> print(df4) key1 key2 C D 0 K0 K0 C0 D0 1 K1 K0 C1 D1 2 K1 K0 C2 D2 3 K2 K0 C3 D3 >>> print(pd.merge(df3, df4, on=['key1','key2'])) # 多个链接键,on是以什么作为参考,必须是基于一个参数的;多个键的连接-值必须是一样的 key1 key2 A B C D #key1=k0,key2=k0看看有没有 -->有, 再看key1=k0,key2=k1有没有 -->没有...... 0 K0 K0 A0 B0 C0 D0 1 K1 K0 A2 B2 C1 D1 2 K1 K0 A2 B2 C2 D2 >>>
>>> pd.merge(df3,df4,on=['key1']) #on以key1为参考值
key1 key2_x A B key2_y C D
0 K0 K0 A0 B0 K0 C0 D0
1 K0 K1 A1 B1 K0 C0 D0 #值可以重复
2 K1 K0 A2 B2 K0 C1 D1
3 K1 K0 A2 B2 K0 C2 D2
4 K2 K1 A3 B3 K0 C3 D3
参数how → 合并方式(how='inner'、how='outer'、how='left'、how='right')
>>> print(pd.merge(df3,df4,on=['key1','key2'],how='inner')) #inner:默认,取交集 ,可不写 key1 key2 A B C D 0 K0 K0 A0 B0 C0 D0 1 K1 K0 A2 B2 C1 D1 2 K1 K0 A2 B2 C2 D2 >>> print(pd.merge(df3,df4,on=['key1','key2'],how='outer')) # outer:取并集,全部都包含上了;数据缺失范围用NaN填充 key1 key2 A B C D 0 K0 K0 A0 B0 C0 D0 1 K0 K1 A1 B1 NaN NaN 2 K1 K0 A2 B2 C1 D1 3 K1 K0 A2 B2 C2 D2 4 K2 K1 A3 B3 NaN NaN 5 K2 K0 NaN NaN C3 D3 >>> print(pd.merge(df3,df4,on=['key1','key2'],how='left')) # left:按照df3为参考合并,数据缺失范围NaN key1 key2 A B C D 0 K0 K0 A0 B0 C0 D0 1 K0 K1 A1 B1 NaN NaN 2 K1 K0 A2 B2 C1 D1 3 K1 K0 A2 B2 C2 D2 4 K2 K1 A3 B3 NaN NaN >>> print(pd.merge(df3,df4,on=['key1','key2'],how='right')) # right:按照df4为参考合并,数据缺失范围NaN key1 key2 A B C D 0 K0 K0 A0 B0 C0 D0 1 K1 K0 A2 B2 C1 D1 2 K1 K0 A2 B2 C2 D2 3 K2 K0 NaN NaN C3 D3 >>>
参数 left_on, right_on, left_index, right_index → 当键不为一个列时,可以单独设置左键与右键
>>> df1 = pd.DataFrame({'lkey':list('bbacaab'), ... 'data1':range(7)}) >>> df2 = pd.DataFrame({'rkey':list('abd'), #lkey,rkey他们两个的名字不一样。 left_on是左边的的DataFrame用这个键,右边的DataFrame用那个键 ... 'date2':range(3)}) #只是个指向问题,相同就用on就可以了 >>> print(df1) lkey data1 0 b 0 1 b 1 2 a 2 3 c 3 4 a 4 5 a 5 6 b 6 >>> print(df2) rkey date2 0 a 0 1 b 1 2 d 2 >>> >>> print(pd.merge(df1,df2,left_on='lkey',right_on='rkey')) # df1以‘lkey’为键,df2以‘rkey’为键; df1里边所有与df2相同的。 lkey data1 rkey date2 #两个key键不一样时,一个是lkey、一个是rkey---> left_on是左边的df1用lkey作为键,righ_on是右边的df2用rkey作为键。 0 b 0 b 1 1 b 1 b 1 2 b 6 b 1 3 a 2 a 0 4 a 4 a 0 5 a 5 a 0
>>> df1 = pd.DataFrame({'key':list('abcdfeg'), # df1以‘key’为键,df2以index为键 ... 'data1':range(7)}) >>> df2 = pd.DataFrame({'date2':range(100,105)}, ... index = list('abcde')) >>> print(df1) key data1 0 a 0 1 b 1 2 c 2 3 d 3 4 f 4 5 e 5 6 g 6 >>> print(df2) date2 a 100 b 101 c 102 d 103 e 104 >>> print(pd.merge(df1, df2, left_on='key', right_index=True))#left_index:为True时,第一个df以index为键,默认False; right_index:为True时,第二个df以index为键,默认False key data1 date2 0 a 0 100 1 b 1 101 2 c 2 102 3 d 3 103 5 e 5 104 >>>
left_on, right_on, left_index, right_index可以相互组合:
left_on + right_on, left_on + right_index, left_index + right_on, left_index + right_index
参数 sort 排序 |
Series 的排序: Series.sort_values(ascending=True, inplace=False) 参数说明:
- ascending:默认为True升序排序,为False降序排序
- inplace:是否修改原始Series
DataFrame 的排序: DataFrame.sort_values(by, ascending=True, inplace=False) 参数说明:
- by:字符串或者List<字符串>,单列排序或者多列排序
- ascending:bool或者List,升序还是降序,如果是list对应by的多列
- inplace:是否修改原始DataFrame
>>> 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(pd.merge(df1,df2,on='key',how='outer')) key data1 date2 0 b 1.0 2.0 1 b 3.0 2.0 2 b 7.0 2.0 3 a 2.0 11.0 4 a 5.0 11.0 5 a 9.0 11.0 6 c 4.0 NaN 7 d NaN 33.0 >>> print(pd.merge(df1,df2,on='key',sort=True,how='outer')) # sort:按照字典顺序通过 连接键 对结果DataFrame进行排序。默认为False,设置为False会大幅提高性能 key data1 date2 0 a 2.0 11.0 1 a 5.0 11.0 2 a 9.0 11.0 3 b 1.0 2.0 4 b 3.0 2.0 5 b 7.0 2.0 6 c 4.0 NaN 7 d NaN 33.0 >>> x2 = pd.merge(df1,df2,on='key',sort=True,how='outer') >>> print(x2.sort_values('data1')) #sort_values('指定某列排序') # 也可直接用Dataframe的排序方法:sort_values,sort_index key data1 date2 3 b 1.0 2.0 0 a 2.0 11.0 4 b 3.0 2.0 6 c 4.0 NaN 1 a 5.0 11.0 5 b 7.0 2.0 2 a 9.0 11.0 7 d NaN 33.0 >>>
>>> x2.sort_index()
key data1 date2
0 a 2.0 11.0
1 a 5.0 11.0
2 a 9.0 11.0
3 b 1.0 2.0
4 b 3.0 2.0
5 b 7.0 2.0
6 c 4.0 NaN
7 d NaN 33.0
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']) >>> print(left) A B K0 A0 B0 K1 A1 B1 K2 A2 B2 >>> print(right) C D K0 C0 D0 K2 C2 D2 K3 C3 D3 >>> print(left.join(right)) #它不是how='inner',而是默认how='left' A B C D K0 A0 B0 C0 D0 K1 A1 B1 NaN NaN K2 A2 B2 C2 D2 >>> print(left.join(right,how='outer')) # 等价于:pd.merge(left, right, left_index=True, right_index=True, how='outer') A B C D K0 A0 B0 C0 D0 K1 A1 B1 NaN NaN K2 A2 B2 C2 D2 K3 NaN NaN C3 D3 >>>
>>> 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) key data1 0 b 1 1 b 3 2 a 2 3 c 4 4 a 5 5 a 9 6 b 7 >>> print(df2) key date2 0 a 11 1 b 2 2 d 33
>>> print(pd.merge(df1,df2,left_index=True,right_index=True,suffixes=('_1','_2'))) #为了区分两个相同的key,合并之后就给它区分了 key_1 data1 key_2 date2 #不加,就是默认为key_x , key_y 即suffixes=('_x','_y')默认哦 0 b 1 a 11 1 b 3 b 2 2 a 2 d 33 >>> print(df1.join(df2['date2'])) key data1 date2 0 b 1 11.0 1 b 3 2.0 2 a 2 33.0 3 c 4 NaN 4 a 5 NaN 5 a 9 NaN 6 b 7 NaN >>> >>> 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']) >>> print(left) A B key 0 A0 B0 K0 1 A1 B1 K1 2 A2 B2 K0 3 A3 B3 K1 >>> print(right) C D K0 C0 D0 K1 C1 D1 >>> print(left.join(right,on='key')) # 等价于pd.merge(left, right, left_on='key', right_index=True, how='left', sort=False);# left的‘key’和right的index A B key C D #这里是left的key,不是right的;left按key,right按index。 0 A0 B0 K0 C0 D0 1 A1 B1 K1 C1 D1 2 A2 B2 K0 C0 D0 3 A3 B3 K1 C1 D1 >>>
>>> left.join(right)
A B key C D
0 A0 B0 K0 NaN NaN
1 A1 B1 K1 NaN NaN
2 A2 B2 K0 NaN NaN
3 A3 B3 K1 NaN NaN
>>>
4.连接与修补 concat、combine_first
连接 - 沿轴执行连接操作
pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
keys=None, levels=None, names=None, verify_integrity=False,
copy=True)
连接:concat
pd.concat([s1,s2]).sort_index() 默认axis=0 .concat([s3,s4], axis=1)
>>> 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(s1) 0 1 1 2 2 3 dtype: int64 >>> print(s2) 0 2 1 3 2 4 dtype: int64 >>> print(s3) a 1 c 2 h 3 dtype: int64 >>> print(s4) b 2 e 3 d 4 dtype: int64 >>> print(pd.concat([s1,s2])) #行与行的拼接呗 0 1 1 2 2 3 0 2 1 3 2 4 dtype: int64 >>> print(pd.concat([s3,s4]).sort_index()) # 默认axis=0,行 拼 行 a 1 b 2 c 2 d 4 e 3 h 3 dtype: int64 >>> >>> print(pd.concat([s3,s4], axis=1)) # axis=1,列+列,成为一个Dataframe 0 1 a 1.0 NaN b NaN 2.0 c 2.0 NaN d NaN 4.0 e NaN 3.0 h 3.0 NaN >>>
连接方式:join,join_axes
pd.concat([s5,s6],axis=1,join='inner') pd.concat([s5,s6],axis=1,join_axes=[['a','b','d']])
>>> s5 = pd.Series([1,2,3],index = ['a','b','c']) >>> s6 = pd.Series([2,3,4],index = ['b','c','d']) >>> print(s5) a 1 b 2 c 3 dtype: int64 >>> print(pd.concat([s5,s6],axis=1)) 0 1 a 1.0 NaN b 2.0 2.0 c 3.0 3.0 d NaN 4.0 >>> print(pd.concat([s5,s6],axis=1,join='inner')) # join:{'inner','outer'},默认为“outer”并集。如何处理其他轴上的索引。 outer为联合,inner为交集。 0 1 #就是把NaN的值行给去掉啊,保留都有值的行 b 2 2 c 3 3 >>> print(pd.concat([s5,s6],axis=1,join_axes=[['a','b','d']])) # join_axes:指定联合的index,只显示a b d轴 0 1 a 1.0 NaN b 2.0 2.0 d NaN 4.0
覆盖列名
pd.concat([s5,s6], keys = ['one','two']) pd.concat([s5,s6], axis=1, keys = ['one','two'])
>>> sre = pd.concat([s5,s6], keys = ['one','two']) >>> print(sre,type(sre)) # keys:序列,默认值无。使用传递的键作为最外层构建层次索引
one a 1 b 2 c 3 two b 2 c 3 d 4 dtype: int64 <class 'pandas.core.series.Series'> >>> print(sre.index) MultiIndex(levels=[['one', 'two'], ['a', 'b', 'c', 'd']], labels=[[0, 0, 0, 1, 1, 1], [0, 1, 2, 1, 2, 3]]) >>> sre = pd.concat([s5,s6], axis=1, keys = ['one','two']) # axis = 1, 覆盖列名 >>> print(sre,type(sre)) one two a 1.0 NaN b 2.0 2.0 c 3.0 3.0 d NaN 4.0 <class 'pandas.core.frame.DataFrame'> >>>
修补 pd.combine_first()
df1.combine_first(df2) df1.update(df2)
>>> 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) 0 1 2 0 NaN 3.0 5.0 1 -4.6 NaN NaN 2 NaN 7.0 NaN >>> print(df2) 0 1 2 1 -42.6 NaN -8.2 2 -5.0 1.6 4.0 >>> print(df1.combine_first(df2)) # 根据index,df1的空值被df2替代; # 如果df2的index多于df1,则更新到df1上,比如index=['a',1] 0 1 2 0 NaN 3.0 5.0 1 -4.6 NaN -8.2 2 -5.0 7.0 4.0 >>>
>>> df1.update(df2) # update,直接df2覆盖df1,相同index位置
>>> print(df1)
0 1 2
0 NaN 3.0 5.0
1 -42.6 NaN -8.2
2 -5.0 1.6 4.0
>>>
5.去重及替换
.duplicated / .replace
去重 .duplicated
s.duplicated()遇到重复的就返回True ; s[s.duplicated() == False] 通过布尔判断去除重复的值 ; s.drop_duplicates() 移除重复值;
>>> s = pd.Series([1,1,1,1,2,2,2,3,4,5,5,5,5]) >>> print(s) 0 1 1 1 2 1 3 1 4 2 5 2 6 2 7 3 8 4 9 5 10 5 11 5 12 5 dtype: int64 >>> print(s.duplicated()) # 判断是否重复 0 False 1 True 2 True 3 True 4 False 5 True 6 True 7 False 8 False 9 False 10 True 11 True 12 True dtype: bool >>> print(s[s.duplicated() == False]) # 通过布尔判断,得到不重复的值 0 1 4 2 7 3 8 4 9 5 dtype: int64 >>> >>> s_re = s.drop_duplicates() # drop.duplicates移除重复 >>> print(s_re) # inplace参数:是否替换原值,默认False 0 1 4 2 7 3 8 4 9 5 dtype: int64 >>> >>> df = pd.DataFrame({'key1':['a','a',3,4,5], ... 'key2':['a','a','b','b','c']}) >>> print(df.duplicated()) 0 False 1 True 2 False 3 False 4 False dtype: bool >>> print(df['key2'].duplicated()) # Dataframe中使用duplicated 0 False 1 True 2 False 3 True 4 False Name: key2, dtype: bool
替换 .replace
s.replace('a', np.nan) s.replace(['a','s'] ,np.nan) 可替换多个值 s.replace({'a':'hello world!','s':123}) 可传入列表或字典
>>> s = pd.Series(list('ascaazsd')) >>> print(s.replace('a', np.nan)) # 可一次性替换一个值或多个值 0 NaN 1 s 2 c 3 NaN 4 NaN 5 z 6 s 7 d dtype: object >>> print(s.replace(['a','s'] ,np.nan)) 0 NaN 1 NaN 2 c 3 NaN 4 NaN 5 z 6 NaN 7 d dtype: object >>> print(s.replace({'a':'hello world!','s':123})) # 可传入列表或字典 0 hello world! 1 123 2 c 3 hello world! 4 hello world! 5 z 6 123 7 d dtype: object >>>
6.数据分组
分组统计 - 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)
以行进行分组是按照数据去进行分;以列进行分组是按字段去分组;
分组
.groupby('A').mean()以A进行分组,算均值; df.groupby(['A'])['D'].mean() 以A进行分组,算D的平均值;
通过分组后的计算,得到一个新的dataframe
默认axis = 0,以行来分组,就是按数据进行分组
可单个或多个([ ])列分组
>>> 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) A B C D 0 foo one -0.362058 -1.232524 1 bar one 1.038853 -1.261056 2 foo two 1.240874 0.120504 3 bar three 0.579106 -0.695712 4 foo two -0.107265 0.149843 5 bar two -0.015046 -1.024002 6 foo one 1.907054 -2.116334 7 foo three -0.826077 -0.959509 >>> >>> print(df.groupby('A'),type(df.groupby('A'))) # 直接分组得到一个groupby对象,是一个中间数据,没有进行计算 <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x000000000B2EA748> <class 'pandas.core.groupby.groupby.DataFrameGroupBy'> >>> >>> a = df.groupby('A').mean()>>> print(a,type(a),'\n',a.columns) C D A bar 0.534304 -0.993590 foo 0.370506 -0.807604 <class 'pandas.core.frame.DataFrame'> Index(['C', 'D'], dtype='object')
>>> b = df.groupby(['A','B']).mean() >>> print(b,type(b),'\n',b.columns) C D A B bar one 1.038853 -1.261056 three 0.579106 -0.695712 two -0.015046 -1.024002 foo one 0.772498 -1.674429 three -0.826077 -0.959509 two 0.566804 0.135173 <class 'pandas.core.frame.DataFrame'> Index(['C', 'D'], dtype='object')
>>> c = df.groupby(['A'])['D'].mean() #以A分组,算D的平均值。 >>> print(c,type(c)) A bar -0.993590 foo -0.807604 Name: D, dtype: float64 <class 'pandas.core.series.Series'> >>>
分组 - 可迭代对象
list(df.groupby('X'))分组后把它变成一个列表(里边嵌套元组) .[0]获取元组;
df.groupby(['X']).get_group('B') 分组后提取出B组
df.groupby('X').groups分组后转化为字典; df.groupby('X').groups['A']转化为字典之后提取出A组;
求直接得到什么组,直接用get_group; groups查看分组后的结构哪几个序列、哪几个index组成的
df.groupby('X').size()查看分组后的长度
df.groupby(['A','B']).groups 按照两个列进行分组; df.groupby(['A','B']).groups[('foo', 'three')]
>>> df = pd.DataFrame({'X' : ['A', 'B', 'A', 'B'], 'Y' : [1, 4, 3, 2]}) >>> print(df) X Y 0 A 1 1 B 4 2 A 3 3 B 2 >>> print(df.groupby('X'), type(df.groupby('X'))) <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x000000000B2D2E48> <class 'pandas.core.groupby.groupby.DataFrameGroupBy'> >>> print(list(df.groupby('X')), '→ 可迭代对象,直接生成list\n') [('A', X Y #'A'后边就是一个dataframe 0 A 1 2 A 3), ('B', X Y 1 B 4 3 B 2)] → 可迭代对象,直接生成list >>> print(list(df.groupby('X'))[0], '→ 以元祖形式显示\n') ('A', X Y 0 A 1 2 A 3) → 以元祖形式显示 >>>for n,g in df.groupby('X'): # n是组名,g是分组后的Dataframe ... print(n) ... print('###') ... print(g) A X Y 0 A 1 2 A 3 ### B X Y 1 B 4 3 B 2 >>> print(df.groupby(['X']).get_group('A'),'\n') X Y 0 A 1 2 A 3 >>> print(df.groupby(['X']).get_group('B'),'\n') # .get_group()提取分组后的组 X Y 1 B 4 3 B 2 >>> grouped = df.groupby(['X'])>>> print(grouped.groups) # .groups:将分组后的groups转为dict {'A': Int64Index([0, 2], dtype='int64'), 'B': Int64Index([1, 3], dtype='int64')} >>> print(grouped.groups['A']) # 也可写:df.groupby('X').groups['A'] # 可以字典索引方法来查看groups里的元素 Int64Index([0, 2], dtype='int64') >>> >>> sz = grouped.size() # .size():查看分组后的长度 >>> print(sz,type(sz)) X A 2 B 2 dtype: int64 <class 'pandas.core.series.Series'> >>>
>>> 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)}) >>> df A B C D 0 foo one -0.742833 -0.459537 1 bar one 1.584006 0.834005 2 foo two -0.021436 0.711519 3 bar three 0.104556 0.693898 4 foo two 0.358998 1.870570 5 bar two 1.626876 0.526132 6 foo one 0.716151 -0.414307 7 foo three -2.315347 -0.258841 >>> df.groupby(['A','B']).groups #按照两个列进行分组,转化为字典; {('bar', 'one'): Int64Index([1], dtype='int64'), ('bar', 'three'): Int64Index([3], dtype='int64'), ('bar', 'two'): Int64Index([5], dtype='int64'), ('foo', 'one'): Int64Index([0, 6], dtype='int64'), (' foo', 'three'): Int64Index([7], dtype='int64'), ('foo', 'two'): Int64Index([2, 4], dtype='int64')} >>> df.groupby(['A','B']).groups[('foo','three')] #查看它的结构; Int64Index([7], dtype='int64') >>> df.groupby(['A','B']).get_group(('foo','three')) #查看它的分组 A B C D 7 foo three -2.315347 -0.258841 >>> df.groupby(['A','B']).get_group(('foo','one')) A B C D 0 foo one -0.742833 -0.459537 6 foo one 0.716151 -0.414307 >>>
其他轴上的分组
按数值类型去分组
df.groupby(df.dtypes, axis=1) df.dtypes得到的是一个Series ;
>>> df = pd.DataFrame({'data1':np.random.rand(2), ... 'data2':np.random.rand(2), ... 'key1':['a','b'], ... 'key2':['one','two']}) >>> print(df) data1 data2 key1 key2 0 0.168619 0.824735 a one 1 0.094004 0.268596 b two >>> print(df.dtypes) #会直接得到一个Series data1 float64 data2 float64 key1 object key2 object dtype: object df = pd.DataFrame({'data1':np.random.rand(2), 'data2':np.random.rand(2), 'key1':['a','b'], 'key2':['one','two']}) >>>for n,p in df.groupby(df.dtypes, axis=1): # 按照值类型分列 #按照列进行分组(没有对值进行聚合),按照数值的字段类型(浮点型、字符串) ... print(n) ... print(p) ... print('##') float64 data1 data2 0 0.204654 0.104438 1 0.749022 0.392701 ## object key1 key2 0 a one 1 b two ##
通过字典或者Series分组
字典的方式一般用在列上;按照行的话a,b对应的是one
df.groupby(mapping, axis=1)
pd.Series(mapping)
>>> df = pd.DataFrame(np.arange(16).reshape(4,4), ... columns = ['a','b','c','d']) >>> df a b c d 0 0 1 2 3 1 4 5 6 7 2 8 9 10 11 3 12 13 14 15 >>> mapping = {'a':'one','b':'one','c':'two','d':'two'} #mapping字典中,a , b 列对应为one; c ,d 列对应two ; >>> df.groupby(mapping, axis = 1) ##以字典来进行分组; <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x000000000299CB70> >>> print(df.groupby(mapping, axis=1).groups['one']) #################特别注意它的结构,a b为它的index,############# Index(['a', 'b'], dtype='object') >>> print(df.groupby(mapping,axis=1).get_group('one')) #查看它的组 a b 0 0 1 1 4 5 2 8 9 3 12 13 >>> df.groupby(mapping, axis = 1).sum() #axis=1是按照行进行计算的 one two 0 1 5 1 9 13 2 17 21 3 25 29 >>>
>>> s = pd.Series(mapping) # s中,index中a、b对应的为one,c、d对应的为two,以Series来分组 >>> print(s,'\n') a one b one c two d two dtype: object >>> print(s.groupby(s).count()) one 2 two 2 dtype: int64 >>>
通过函数分组
>>> df = pd.DataFrame(np.arange(16).reshape(4,4), ... columns = ['a','b','c','d'], ... index = ['abc','bcd','aa','b']) >>> print(df,'\n') a b c d abc 0 1 2 3 bcd 4 5 6 7 aa 8 9 10 11 b 12 13 14 15 >>> print(df.groupby(len).sum()) # 按照index的字母长度分组; a b c d 1 12 13 14 15 2 8 9 10 11 3 4 6 8 10 >>>
分组计算函数方法
>>> 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) <pandas.core.groupby.groupby.SeriesGroupBy object at 0x000000000B2D2B38> >>> print(grouped.first(),'→ first:非NaN的第一个值\n') 1 1 2 2 3 3 dtype: int64 → first:非NaN的第一个值 >>> print(grouped.last(),'→ last:非NaN的最后一个值\n') 1 10 2 20 3 30 dtype: int64 → last:非NaN的最后一个值 >>> print(grouped.sum(),'→ sum:非NaN的和\n') 1 11 2 22 3 33 dtype: int64 → sum:非NaN的和 >>> print(grouped.mean(),'→ mean:非NaN的平均值\n') 1 5.5 2 11.0 3 16.5 dtype: float64 → mean:非NaN的平均值 >>> print(grouped.median(),'→ median:非NaN的算术中位数\n') 1 5.5 2 11.0 3 16.5 dtype: float64 → median:非NaN的算术中位数 >>> print(grouped.count(),'→ count:非NaN的值\n') 1 2 2 2 3 2 dtype: int64 → count:非NaN的值 >>> print(grouped.min(),'→ min、max:非NaN的最小值、最大值\n') 1 1 2 2 3 3 dtype: int64 → min、max:非NaN的最小值、最大值 >>> print(grouped.std(),'→ std,var:非NaN的标准差和方差\n') 1 6.363961 2 12.727922 3 19.091883 dtype: float64 → std,var:非NaN的标准差和方差 >>> print(grouped.prod(),'→ prod:非NaN的积\n') 1 10 2 40 3 90 dtype: int64 → prod:非NaN的积 >>>
多函数计算:agg()
df.groupby('a').agg(['mean',np.sum]) 、 df.groupby('a')['b'].agg({'result1':np.mean,'result2':np.sum})
>>> 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) a b c d 0 1 0.296927 0.088159 0.144423 1 1 0.658442 0.172187 0.716124 2 2 0.978164 0.292865 0.421377 3 2 0.288031 0.874687 0.779844 >>> print(df.groupby('a').agg(['mean',np.sum])) #以a进行分组,想求出它的均值和sum b c d mean sum mean sum mean sum a 1 0.477684 0.955369 0.130173 0.260346 0.430273 0.860547 2 0.633097 1.266195 0.583776 1.167551 0.600611 1.201221 >>> print(df.groupby('a')['b'].agg({'result1':np.mean, #把b单独提取出来,结果以字典的形式显示。 ... 'result2':np.sum})) result1 result2 a 1 0.477684 0.955369 2 0.633097 1.266195 >>> # 函数写法可以用str,或者np.方法 # 可以通过list,dict传入,当用dict时,key名为columns
7.分组转换及一般性“拆分-应用apply-合并”
transform / apply
数据分组转换,transform
df.groupby('key2').transform(np.mean)
>>> 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() >>> print(df) data1 data2 key1 key2 0 0.965986 0.086595 a one 1 0.981811 0.143423 a two 2 0.750037 0.331594 b one 3 0.433544 0.594493 b two 4 0.801283 0.022557 a one >>> print(k_mean) data1 data2 key1 a 0.91636 0.084192 b 0.59179 0.463044 >>> print(pd.merge(df,k_mean,left_on='key1',right_index=True).add_prefix('mean_')) # .add_prefix('mean_'):添加前缀 # 通过分组、合并,得到一个包含均值的Dataframe mean_data1_x mean_data2_x mean_key1 mean_key2 mean_data1_y mean_data2_y 0 0.965986 0.086595 a one 0.91636 0.084192 1 0.981811 0.143423 a two 0.91636 0.084192 4 0.801283 0.022557 a one 0.91636 0.084192 2 0.750037 0.331594 b one 0.59179 0.463044 3 0.433544 0.594493 b two 0.59179 0.463044 >>> >>> print(df.groupby('key2').mean()) # 按照key2分组求均值 data1 data2 key2 one 0.839102 0.146916 two 0.707678 0.368958 >>> print(df.groupby('key2').transform(np.mean)) data1 data2 0 0.839102 0.146916 1 0.707678 0.368958 2 0.839102 0.146916 3 0.707678 0.368958 4 0.839102 0.146916 >>> data1、data2每个位置元素取对应分组列的均值 # 字符串不能进行计算
一般化Groupby方法:apply
apply是你可以自己去创建一个函数,分组之后按照你这个函数去运行
>>> df = pd.DataFrame({'data1':np.random.rand(5), ... 'data2':np.random.rand(5), ... 'key1':list('aabba'), ... 'key2':['one','two','one','two','one']}) >>> >>> print(df.groupby('key1').apply(lambda x: x.describe())) # apply直接运行其中的函数 # 这里为匿名函数,直接描述分组后的统计量 data1 data2 # describe()就是计算统计量。 key1 a count 3.000000 3.000000 mean 0.544703 0.643239 std 0.423421 0.373472 min 0.093693 0.217797 25% 0.350207 0.506341 50% 0.606721 0.794885 75% 0.770208 0.855961 max 0.933696 0.917036 b count 2.000000 2.000000 mean 0.560306 0.296463 std 0.081378 0.365345 min 0.502763 0.038125 25% 0.531534 0.167294 50% 0.560306 0.296463 75% 0.589077 0.425632 max 0.617848 0.554801 >>> def f_df1(d,n): return(d.sort_index()[:n]) # 参数n就是返回几个; def f_df2(d,k1): return(d[k1]) print(df.groupby('key1').apply(f_df1,2),'\n') #第一个参数d就是dataframe data1 data2 key1 key2 key1 a 0 0.913408 0.369516 a one 1 0.742166 0.340193 a two b 2 0.975362 0.863833 b one 3 0.087291 0.420579 b two print(df.groupby('key1').apply(f_df2,'data2')) #按照key1分组之后按照data2做了个索引; key1 a 0 0.233298 1 0.024352 4 0.828523 b 2 0.340762 3 0.745267 Name: data2, dtype: float64 print(type(df.groupby('key1').apply(f_df2,'data2'))) <class 'pandas.core.series.Series'> # f_df1函数:返回排序后的前n行数据 # f_df2函数:返回分组后表的k1列,结果为Series,层次化索引 # 直接运行f_df函数 # 参数直接写在后面,也可以为.apply(f_df,n = 2))
8.透视表及交叉表
类似excel数据透视 - pivot table / crosstab ;groupby是按照逻辑,pivot table透视表是按照功能
透视表:pivot_table
# pd.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
pd.pivot_table(df, values = 'values', index = 'date', columns = 'key', aggfunc=np.sum)
>>> 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) date key values 0 2017-05-01 a 9.990137 1 2017-05-02 b 0.888088 2 2017-05-03 c 9.568805 3 2017-05-01 d 3.617859 4 2017-05-02 a 6.341511 5 2017-05-03 b 5.447269 6 2017-05-01 c 7.827543 7 2017-05-02 d 9.753436 8 2017-05-03 a 6.048343 >>> print(pd.pivot_table(df, values = 'values', index = 'date', columns = 'key', aggfunc=np.sum)) # 也可以写 aggfunc='sum' key a b c d date 2017-05-01 9.990137 NaN 7.827543 3.617859 2017-05-02 6.341511 0.888088 NaN 9.753436 2017-05-03 6.048343 5.447269 9.568805 NaN >>> # data:DataFrame对象 ... # values:要聚合的列或列的列表。 就是df里边的数据,分组的结果聚合哪些数据; ... # index:是做完数据透视表之后的index,从原数据的列中筛选。 要以哪个值作为参考,数据透视表后的那个index就是分组的那个index,拿哪个字段作为分组; ... # columns:数据透视表的columns,从原数据的列中筛选 ... # aggfunc:用于聚合的函数,默认为numpy.mean,支持numpy计算方法 ... >>> print(pd.pivot_table(df, values = 'values', index = ['date','key'], aggfunc=len)) values date key 2017-05-01 a 1.0 c 1.0 d 1.0 2017-05-02 a 1.0 b 1.0 d 1.0 2017-05-03 a 1.0 b 1.0 c 1.0 >>> # 这里就分别以date、key共同做数据透视,值为values:统计不同(date,key)情况下values的平均值 ... # aggfunc=len(或者count):计数
交叉表: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]}) >>> print(df) A B C 0 1 3 1.0 1 2 3 1.0 2 2 4 NaN 3 2 4 1.0 4 2 4 1.0 >>> print(pd.crosstab(df['A'],df['B'])) # 如果crosstab只接收两个Series,它将提供一个频率表。 #用A的唯一值,统计B唯一值的出现次数 B 3 4 #当A值为1,B值为3时,有1个; A为2,B为3时有1个; A为2,B为4时有3个。 A 1 1 0 2 1 3 >>> print(pd.crosstab(df['A'],df['B'],normalize=True)) # normalize:默认False,将所有值除以值的总和进行归一化 → 为True时候显示百分比 B 3 4 #就是说当A为1,B为3时,有1个,1/(1+1+0+3)=0.2 这样一个百分比。 A 1 0.2 0.0 2 0.2 0.6 >>> print(pd.crosstab(df['A'],df['B'],values=df['C'],aggfunc=np.sum)) # values:可选,根据因子聚合的值数组 # aggfunc:可选,如果未传递values数组,则计算频率表,如果传递数组,则按照指定计算 # 这里相当于以A和B界定分组,计算出每组中第三个系列C的值 B 3 4 #就是说当A=1,B=3时,求C列的和为1 。 A 1 1.0 NaN 2 1.0 2.0 >>> print(pd.crosstab(df['A'],df['B'],values=df['C'],aggfunc=np.sum, margins=True)) # margins:布尔值,默认值False,给你加个行/列边距(小计),为了好看点 B 3 4 All A 1 1.0 NaN 1.0 2 1.0 2.0 3.0 All 2.0 2.0 4.0 >>>
9.数据读取
核心:read_table, read_csv, read_excel
C:\Users\Administrator>pip install xlrd Collecting xlrd #先安装下这个模块 Downloading https://files.pythonhosted.org/packages/07/e6/e95c4eec6221bfd8528bcc4ea252a850bf 100% |████████████████████████████████| 112kB 171kB/s Installing collected packages: xlrd Successfully installed xlrd-1.1.0
读取普通分隔数据:read_table,可以读取txt,csv
import os os.chdir(r'C:\Users\Administrator\Desktop') data1 = pd.read_table('data1.txt', delimiter=',',header = 0, index_col=1) # delimiter:用于拆分的字符,也可以用sep:sep = ','#header:用做列名的序号,默认为0(第一行) # index_col:指定某列为行索引,否则自动索引0, 1, ..... print(data1) header=0就是把首行第一行作为columns #index_col=0就是把第一列当做索引,不写它或None就是默认的自动添加; va1 va3 va4 va2 2 1 3 4 3 2 4 5 4 3 5 6 5 4 6 7 读取csv数据:read_csv # 先熟悉一下excel怎么导出csv data2 = pd.read_csv('地市级党委书记数据库(2000-10).csv',engine = 'python',encoding='utf-8') # engine:使用的分析引擎。可以选择C或者是python。C引擎快但是Python引擎功能更加完备。 # encoding:指定字符集类型,即编码,通常指定为'utf-8' # 大多数情况先将excel导出csv,再读取 print(data2.head()) # read_table主要用于读取简单的数据,txt/csv 省级政区代码 省级政区名称 地市级政区代码 地市级政区名称 年份 ... 专业:理工 专业:农科 专业:医科 入党年份 工作年份 0 130000 河北省 130100 石家庄市 2000 ... NaN NaN NaN NaN NaN 1 130000 河北省 130100 石家庄市 2001 ... 1.0 0.0 0.0 NaN NaN 2 130000 河北省 130100 石家庄市 2002 ... 1.0 0.0 0.0 NaN NaN 3 130000 河北省 130100 石家庄市 2003 ... 1.0 0.0 0.0 NaN NaN 4 130000 河北省 130100 石家庄市 2004 ... 1.0 0.0 0.0 NaN NaN [5 rows x 23 columns] 读取excel数据:read_excel data3 = pd.read_excel('地市级党委书记数据库(2000-10).xlsx',sheetname='中国人民共和国地市级党委书记数据库(2000-10)',header=0) # io :文件路径。 sheetname就是你的excel文件里边可能有多个文件,你可以写文件名也可以写 0就是第一个文件,1第二个文件;None是给你读取成个字典,把excel里边两个表都读出来;list就是 [0,1] # sheetname:返回多表使用sheetname=[0,1],若sheetname=None是返回全表 → ① int/string 返回的是dataframe ②而none和list返回的是dict # header:指定列名行,默认0,即取第一行 # index_col:指定列为索引列,也可以使用u”strings” print(data3) 省级政区代码 省级政区名称 地市级政区代码 地市级政区名称 ... 专业:农科 专业:医科 入党年份 工作年份 0 130000 河北省 130100 石家庄市 ... NaN NaN NaN NaN 1 130000 河北省 130100 石家庄市 ... 0.0 0.0 NaN NaN 2 130000 河北省 130100 石家庄市 ... 0.0 0.0 NaN NaN 3 130000 河北省 130100 石家庄市 ... 0.0 0.0 NaN NaN 4 130000 河北省 130100 石家庄市 ... 0.0 0.0 NaN NaN 5 130000 河北省 130100 石家庄市 ... 0.0 0.0 NaN NaN ... 3661 650000 新疆维吾尔自治区 654300 阿勒泰地区 ... NaN NaN NaN NaN 3662 650000 新疆维吾尔自治区 654300 阿勒泰地区 ... NaN NaN NaN NaN [3663 rows x 23 columns]