![0cefc8e0663b0db916e8ed37f21d1447.png](https://i-blog.csdnimg.cn/blog_migrate/52b5a5bed4bd17bb3cfcda1d894d3a4c.jpeg)
内容目录
- DataFrame简介
- DataFrame创建方式
- DataFrame索引和切片
- DataFrame属性
- DataFrame级联与合并
- DataFrame基本操作
- DataFrame分组聚合操作
- DataFrame数据透视与交叉表
1 DataFrame简介
我们在上次课中讲到了Pandas的Series结构,还没看的点这里
ailsa:python数据分析:Pandas之Serieszhuanlan.zhihu.com![c572856bad38ed9381d740afb469b97c.png](https://i-blog.csdnimg.cn/blog_migrate/bfe8a0c31419fd5e1a20bd763aa0c797.jpeg)
DataFrame是一个[表格型]的数据结构,DataFrame由按一定顺序排列的多列数据组成.设计,初衷是将Series的使用场景从一维拓展到多维。其实DataFrame就是由多个Series组成的,因此可以说DataFrame是Series的容器。
DataFrame由3部分组成
行索引:index
列索引:columns
值:values
长这个样子
![48e1d97d2d361543ccecfa28d3e713e8.png](https://i-blog.csdnimg.cn/blog_migrate/4a61f760365fee1bf7166d99f0e1416b.png)
是不是感觉跟Excel表格很像,跟关系型数据库表也很像,跟SPSS的表也像吧,没错,他们都是极其相似的二维表,这种形式的发明还要追溯到1978年的世界上第一款电子表格Visicalc,想要了解,可以戳这里 ailsa:1.Excel数据分析:Excel最最最基础的操作 有讲到电子表格的发展史,由此可见,二维表对于数据分析还是挺便捷的,要不然咋会有这么多分析软件都采用这种形式呢。那对于DataFrame的学习,大家可以把它想象成excel,原理都是一样的,只是一个是用鼠标点点点,一个是代码敲敲敲。
2 DataFrame创建方式
2.1 使用ndarry创建
# DataFrame的参数组成 pd.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
# index指定行索引,columns指定列索引,若不写,则默认从0开始,size指定行数和列数
df = pd.DataFrame(data=np.random.randint(1,10,size=(2,4)),index=["a","b"],columns=["A","B","C","D"])
![a5b818f8004782e3c8ef64bf77abc435.png](https://i-blog.csdnimg.cn/blog_migrate/e2d2ba167fe4e344c94ed072e8b0cfcf.png)
2.2 使用字典创建
dic = {"name":["张三","李四","王五"],"age":[1,2,3]}
# key为列的索引,行索引则默认从0开始
pd.DataFrame(dic)
![b2b15173d3443c2a29b31c8f34e50894.png](https://i-blog.csdnimg.cn/blog_migrate/a623749d1e7f55e02b86435f7ad09c5f.png)
可以看出,以字典形式创建,DataFrame以字典的key作为每一列的列名,以字典的值(一个数组)作为每一列的值,DataFrame会自动加上每一行的索引
3 DataFrame的索引和切片
DataFrame也是分为显示索引和隐式索引
3.1 隐式索引的操作
df = pd.DataFrame(data=np.random.randint(1,10,size=(3,4)))
![16769f1a503de86372f94319e360ffed.png](https://i-blog.csdnimg.cn/blog_migrate/22ffe91052db10c3abff45e7534fa6dd.png)
- df[0][0] df[列][行],获取隐式索引单个元素
- df[0:2] 对行的切片操作,获取的是0和1行,顾头不顾尾
- df[[0,1]] 对列的操作,获取第一列和第二列,跟Series不同
- df.iloc[0:2,0:2] iloc对于隐式索引的操作,获取前两行和前两列组成的区域,逗号前式行,逗号后是列
- df.iloc[[0,1],[0,1]] iloc对于隐式索引的操作,获取前两行和前两列组成的区域
3.2 显式索引的操作
df1 = pd.DataFrame(data=np.random.randint(1,10,size=(3,4)),index=["a","b","c"],columns=["A","B","C","D"])
![1dbb8d39bc9de55e7c83ebc44ecfc6e0.png](https://i-blog.csdnimg.cn/blog_migrate/9d8d251bb03e3e2afe7ad8629cd3a4fc.png)
- df["A"] 或 df.A 获取单列,类似于字典的操作
- df['A']['a'] 获取单个元素,先列后行 df[列][行]
- df["a":"b"] 获取是a到b行,包含b行
- df[["A","B"]] 获取A列和B列
- df.loc["a":"b","A":"B"] loc对于显式索引的操作,df[行区域,列区域]
- df.loc[["a","b"],["A","B"]] loc对于显式索引的操作,结果同上
总结
1.DataFrame相对于Series而言,多了对于列的操作,但是是建立在Series基础之上。
2.loc是对于显式索引的相关操作(对于标签的处理),iloc是针对隐式索引的相关操作(对于整数的处理)。
3.df[0:2]切片操作是针对行而言,对于df["A"]索引操作是对于列而言;获取单个元素先列后行,df[列][行];loc和iloc操作,逗号前是行区域或行列表,逗号后是列区域或列列表。
4 DataFrame 的属性
df.values 值
df.columns 列
df.index 行
df.shape 几行几列(行,列)
df.size 大小,行数X列数
,以上面的df为事例
![d9227d11351dcd98a84f683b1ac0a10e.png](https://i-blog.csdnimg.cn/blog_migrate/e42bd8d465de078b2d76cbdd017ef51b.png)
5 DataFrame的级联与合并
- 级联:pd.concat,pd.append
- 合并:pd.merge,pd.join
5.1 级联
功能:根据指定的行或列进行值的拼接,不参与任何计算,只是把多个df变成1个
pd.concat()参数(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=None, copy=True)
- axis=0 列方向级联拼接,axis=1行方向级联拼接,默认为0
- join为级联方式,outer会将所有的项进行级联(忽略匹配和不匹配),取并集,而inner只会将匹配的项级联到一起,不匹配的不级联,取交集。
- join_axes index对象列表,用于其他n-1轴的特定索引,可以指定根据哪个轴来对齐数据
- ignore_index boolean,default False。如果为True,请不要使用并置轴上的索引值。结果轴将被标记为0,...,n-1。如果要连接其中并置轴没有有意义的索引信息的对象,这将非常有用。注意,其他轴上的索引值在连接中不受影响。
- keys 序列,默认值无。使用传递的键作为最外层构建层次索引。如果为多索引,应该使用元组。
- levels 序列列表,默认值无。用于构建MultiIndex的特定级别(唯一值)。否则,它们将从键推断。
- names:list,default无。结果层次索引中的级别的名称。
示例数据
dic1 = {'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']}
dic2 = {'A': ['A4', 'A5', 'A6', 'A7'],
'B': ['B4', 'B5', 'B6', 'B7'],
'C': ['C4', 'C5', 'C6', 'C7'],
'D': ['D4', 'D5', 'D6', 'D7']}
dic3 = {'A': ['A8', 'A9', 'A10', 'A11'],
'B': ['B8', 'B9', 'B10', 'B11'],
'C': ['C8', 'C9', 'C10', 'C11'],
'D': ['D8', 'D9', 'D10', 'D11']}
df1 = pd.DataFrame(dic1,index=[0, 1, 2, 3])
df2 = pd.DataFrame(dic2, index=[4, 5, 6, 7])
df3 = pd.DataFrame(dic3, index=[8, 9, 10, 11])
pd.concat([df1,df2,df3]) # 默认是按照列方向
![b3faed212eff030321e7d785ec099000.png](https://i-blog.csdnimg.cn/blog_migrate/b22549f112b36531c5c7f095b962c963.png)
keys使用,作用于不同层级的名称
pd.concat([df1,df2,df3],keys=['x', 'y', 'z']) # ('x', 'y', 'z')元组也可以
![79af3275c3c9dc35d2ba9c19f789794d.png](https://i-blog.csdnimg.cn/blog_migrate/9f42cd3f9b3070d092c8811bd4e32e76.png)
使用ignor_index
# 创建df4
dic4={'a':[1,2,3,4],'b':[5,6,7,8]}
df4 = pd.DataFrame(dic4)
df4
![34edc3bc2d4712805e141f29887e94b5.png](https://i-blog.csdnimg.cn/blog_migrate/603836e09b9a7f7c0b5246e2d683062f.png)
pd.concat([df1,df4],axis=1,ignore_index=True) # 行方向进行级联
![1ae3ebdb274661f4a90260c9c5aeb6a2.png](https://i-blog.csdnimg.cn/blog_migrate/ca51b54b41a061e1b9ee376ba79ee613.png)
join_axes,可以指定根据哪个轴来对齐数据
#新增df5
dic5={'a':[1,2,3,4],'b':[5,6,7,8]}
df5= pd.DataFrame(dic5,index=[2,3,4,5])
df5
![3ed25f6331f1057963d217ca9c34eef0.png](https://i-blog.csdnimg.cn/blog_migrate/af61760df546916453954d55fea07f97.png)
df1和df5行方面拼接,只有2和3是一样的
d.concat([df1,df5],axis=1,join_axes=[df1.index])
![913df2909952c0350514b4fe1ed0b65c.png](https://i-blog.csdnimg.cn/blog_migrate/32debc4b719cb4f99d42597a12820b29.png)
效果类似于按照df1的行索引进行级联,df1的所有行会显示,而df5只能显示匹配上的
join的用法,取并集或交集
pd.concat([df1,df5],axis=1,join='outer') # 取并集,缺失值显示为NaN
![efc1033b7e73bd3ef33000d722373fe7.png](https://i-blog.csdnimg.cn/blog_migrate/bb1d01a50c10270534df725d444b3bf9.png)
pd.concat([df1,df5],axis=1,join='inner') # 取交集
![e67aba624d0edddf8f037d5dfb9f49d8.png](https://i-blog.csdnimg.cn/blog_migrate/0179d4a1552b035531c883a485425df5.png)
df.append()方法,类似于添加的意思
df1.append参数:(other, ignore_index=False, verify_integrity=False, sort=None)
默认是列方向级联,跟concat的默认方式是一样的
df1.append(df2)
![8e034f42d08e726c44dc4d2e75d19d5c.png](https://i-blog.csdnimg.cn/blog_migrate/aa589e546a55c48282fe59417be298ae.png)
这种方式操作更简单,后面会经常使用
5.2 合并
pd.merge() 跟SQL中的连表查询很像,需要根据合并条件进行两表合并,也就是两个DataFrame需要具有相同的列,然后再进行条件连接合并,而concat单纯根据索引就能进行拼接。
参数;pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)
- left 和right 定义左表和右表,指定需要连接的两个DateFrame
- how连接方式 {'left', 'right', 'outer', 'inner'}, 默认'inner'
- inner 内连接,只连接两个DataFrame的交集
- left 左连接,以左表为主,会显示左表全部内容,右表根据左表匹配,未匹配上不显示
- right 右连接,以右表为主
- outer 全外连接,会显示所有内容
- on 如果两个Frame 指定连接条件的列名一致,可以使用这种方式
- left_on 当两个frame列名不一致时,根据定义的左表和右表分别定义连接的字段名
- right_on 当两个frame列名不一致时,根据定义的左表和右表分别定义连接的字段名
- left_index 为True时,代表以索引作为连接条件
- right_index 同上
示例
两个DataFrame列名相同且内容一致,默认自动连接
dic1 = {"name":["A","B","C","D"],"age":[20,21,22,23]}
dic2 = {"name":["A","C","D","F"],"sex":["M","F","M","M"]}
df1 = pd.DataFrame(dic1)
df2 = pd.DataFrame(dic2)
pd.merge(df1,df2) # name一列相同,自动连接
或者 pd.merge(df1,df2,on="name")
![5aa785413993613133ee37558f8f79f1.png](https://i-blog.csdnimg.cn/blog_migrate/fd1ec32c975da11a3d197f4c4618adde.png)
当连接条件列名不一致时,使用lefton 和 right_on
emp_dic = {"姓名":["张三","李四","王五"],"dep_id":[1,2,3]}
dep_dic = {"id":[1,2],"部门名称":["销售部","运营部"]}
emp = pd.DataFrame(emp_dic)
dep = pd.DataFrame(dep_dic)
pd.merge(emp,dep,left_on="dep_id",right_on="id")
SQL: select * from emp e left join dep d on e.dep_id = d.id
![ab3bdf2f26b2277cd259760821e77d75.png](https://i-blog.csdnimg.cn/blog_migrate/ab83d6a74f97add872ecf33c7264576e.png)
当连接条件为索引时,可以使用left_index 和 righti_ndex
pd.merge(emp,dep,left_on="dep_id",right_index=True) # dep_id 与dep的行索引进行匹配
![5399f41c0ad655f70fbc12a3b2c4de6d.png](https://i-blog.csdnimg.cn/blog_migrate/b7d7b3807d00ab313fe4395d9c3d33fd.png)
6 DataFrame的基本操作
6.1 缺失值处理
# 在np中
None是python自带的,其类型为object,因此,None不能参与到人任何计算中(NoneType)
np.nan(NaN) 是浮点类型(float),能参与到计算中.但计算的结果总是NaN
# 在pandas中
把None和np.nan都视作np.nan
构建示例数据
df = pd.DataFrame(np.random.randint(1,100,size=(5,4)),index=["a","b","c","d","e"],columns=["A","B","C","D"])
df1 = pd.DataFrame(data=np.random.randint(1,10,size=(3,4)),index=["a","b","c"],columns=["A","B","C","D"])
df3 = pd.concat([df1,df],axis=1) # concat级联,axis=1 行方向,后面会讲
df3
![a5149bb3801db53e301a0e46f8bc9522.png](https://i-blog.csdnimg.cn/blog_migrate/dfd6fed03812dd7ca080e6ee5c0867d3.png)
6.1.1 查看哪些行或列为存在缺失值
- isnull() 有缺失值则返回True
- notnull() 没有缺失值则返回True
- isnull().any(axis=1) axis=1是代表行,0代表列,一行中只要有一个空值则返回True
- notnull().all(axis=1) 一行中所有不为空则返回True
df3.notnull()
![b8cda58d1fe541155ee33fc71acdf04e.png](https://i-blog.csdnimg.cn/blog_migrate/90bf704071a59c2fc854d7a53fb89a1d.png)
df3.notnull().all(axis=1)
![bd560fa04eaf9684182a2ac366914522.png](https://i-blog.csdnimg.cn/blog_migrate/8d731413a0bc28499b133e1318cf4855.png)
6.1.2 删除有缺失值的行或列
df.dropna() 删除有缺失值的整行或整列
f3.dropna的参数:(axis=0, how='any', thresh=None, subset=None, inplace=False)
- axis=0 这里的0代表行,在drop操作中0代表行,1代表列,根据axis的设置决定是对行还是列
- how='any' how是删除方式,any只要一行或一列中有一个缺失值就删除,还有一个all代表的意思是,一行或一列中所有的都为缺失值才删除,常用的是any
- inplace=False inplace代表操作是否对原数据进行覆盖,False代表不在原数据上修改,而是复制出一份,True代表在原数据上修改。
df3.dropna()
![4c11e79e39bb9398d357083e52c4bffe.png](https://i-blog.csdnimg.cn/blog_migrate/acd073dcd6ddc0e06d8d3c0a1e448f27.png)
6.1.3 填充缺失值
df.fillna() 对缺失值进行填充
df.fillna参数:(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)
- value 填充的值,也可以是字典
- axis 1 代表行,0代表列 ,结合method使用,决定了填充是按照行还是列
- inplace inplace代表操作是否对原数据进行覆盖,False代表不在原数据上修改,而是复制出一份,True代表在原数据上修改。
- method 分为四种填充方式:'backfill', 'bfill', 'pad', 'ffill' 其中pad / ffill表示用前面行/列的值,填充当前行/列的空值; backfill / bfill表示用后面行/列的值,填充当前行/列的空值。
需求1:把缺失值都填充为6
df3.fillna(6)
![46c2698dd622d8585a3aa50539ac2835.png](https://i-blog.csdnimg.cn/blog_migrate/cc64991a21808b1c1cb69bdfc470a04e.png)
需求2:把缺失值按照列方向,填充为前面的那个值
df3.fillna(axis=0,method="ffill") # 改成pad也可以,axis确定了填充的方向,如果不写,默认是列
![a1cf069608dbf91349c1136ef76458ea.png](https://i-blog.csdnimg.cn/blog_migrate/05fdb329f663419a8a00716387798ac6.png)
需求3:把缺失值按照行方向,填充为后面的那个值
df3.fillna(axis=1,method="bfill")# 改成backfill也可以,axis确定了填充的方向,如果不写,
![cdb70d680012e69d9d98cd217b164810.png](https://i-blog.csdnimg.cn/blog_migrate/66fc14afe662ce8e973e69dcd2edeaa3.png)
6.2 重复值处理
6.2.1 df.duplicated() 查看重复行
df.duplicated()的参数:(subset=None, keep='first')
- subset 指定是哪几列重复,默认是所有的列
- keep 有{'first', 'last', False}几种方式, 默认 'first'
- first 将重复项标记为“`True`”,除了第一次出现
- last:将重复项标记为``True`,除了最后一次出现
- False:将所有重复项标记为“True”
直接通过示例就能明白了
创建一个DataFrame
dic = {"A":[1,1,1,5,9],"B":[5,5,6,7,7],"C":[6,6,5,2,8]}
df = pd.DataFrame(dic)
df
![2af1f7f955d0131af6ae5cb6ad0fbc41.png](https://i-blog.csdnimg.cn/blog_migrate/c374e9e705e466945e825807dd5f3eac.png)
需求1:把所有列重复的的行标注出来
df.duplicated() # keep默认为first,subset默认为所有的列,意思就是所有的列同时重复才显示
![0848d968d50bc51c7729752c5c96845f.png](https://i-blog.csdnimg.cn/blog_migrate/58ee49d15b5d52a3c9baa07965976e05.png)
我们发现第一行和第二行所有列一样,根据keep设置的first的原则,第一次出现的不显示为True,其余的显示为True,这里的True代表重复的意思,我们只要把True的删除,就可以保留唯一值了。
需求2:把A和B两列同时重复的行显示,要求最后的那个不标注为True
df.duplicated(subset=["A","B"],keep='last')
![fcd7fb07ff7bcbf283153c7f36d0b5ad.png](https://i-blog.csdnimg.cn/blog_migrate/28a4a8134860652ec1b2bba1b63bc25f.png)
我们发现A和B两列同时重复的还是第一行和第二行,设置keep为last之后,第一行显示为重复行,为True,第二行显示为False。
需求3:把A和B两列重复的行全部显示为True
df.duplicated(subset=["A","B"],keep=False)
![5703c8a51a701222b679244eb31fc087.png](https://i-blog.csdnimg.cn/blog_migrate/573c443e30230b842d9f8bb0f698292f.png)
keep设置为False之后,所有重复的行都会显示为True
6.2.2 删除重复行,保留唯一值
对于重复行的处理,我们一般都是找出重复行,只保留一个,删除其他的,那duplicated通过keep设置来让用户自由选择是保留第一个,还是最后一个,通过显示True来实现该功能
df.drop_duplicates() 删除重复值
df.drop_duplicates参数:(subset=None, keep='first', inplace=False)
前两个就不说了,跟duplicated一样
inplace=False不在原值上删除,而是复制出一份进行操作,改成True则直接对df进行删除操作,这个也是pandas谨慎的地方,大部分操作都不是在原值上进行的,如果需要可以通过inplace进行设置
需求:删除所有列同时重复的行,默认保留第一个就行
df.drop_duplicates() # 把返回True给删除,很简便
![fd4c02f640ccc5241597a2dfa94d939a.png](https://i-blog.csdnimg.cn/blog_migrate/423cf7bf4287bfbba16888dc171075b3.png)
注意:此操作之后,原df并没有发生变化,有两种处理方式,第一种:把删除后的数据赋值给新的变量,第二种:直接修改inplace=True。
6.3 排序
- df.sort_index() 按索引排序
- df.sort_value() 按值排序
常用的是纵向排序,也就是默认的axis=0的相关操作
sort_index()参数(axis=0, level=None, ascending=True, inplace=False, kind='quicksort', na_position='last', sort_remaining=True, by=None)
- axis=0 纵向排序(行索引),axis=1 横向排序(列索引)
- ascending 排序方式,True为升序,False为降序
- kind排序方式,默认是quicksort 快排
df=df.take(np.random.permutation(5),axis=0)
df
![1c4022e426af6fa2043b25d5a6feb76b.png](https://i-blog.csdnimg.cn/blog_migrate/7fe54c381c7ab9cc18f336a78a93c7ec.png)
df.sort_index()
![f366f4e7005b1961f310e24be11f010b.png](https://i-blog.csdnimg.cn/blog_migrate/656cc62b407308ec6cd4ae578791f51f.png)
df.sort_values()
参数:(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last')
- axis=0 纵向排序(index),axis=1 横向排序(columns)
- ascending = True 升序,False降序
- inplace 是否在原值上直接修改,False是重新复制出一份,原frame不变
- kind排序方式 {'quicksort', 'mergesort', 'heapsort'} 默认是quicksort 快排,mergesort归并排序,heapsort 堆排序
对某列进行排序
df.sort_values(by="C")
![04c23312f0c60232829cafd30b48dbce.png](https://i-blog.csdnimg.cn/blog_migrate/b2ee07c2d1f01d4b95ecd5b09f8f3cfd.png)
df.sort_values(by=["C","B"],axis=0,ascending=[False,True])
![ec357d5013e3afc861574842dc7e07b4.png](https://i-blog.csdnimg.cn/blog_migrate/05e9f2bd1ead7c45ce11ec0a8e10861f.png)
对行进行排序
df.sort_values(by=[0,2],ascending=[False,True],axis=1)
![31376630cb418db84a82363057be4b88.png](https://i-blog.csdnimg.cn/blog_migrate/eb5e75db8c596d27a7e01b078e137df1.png)
注:当存在多列或多行排序时,是有优先顺序的,根据列表中的优先顺序,在前面的优先级高,越往后优先级越低。
- np.random.shuffle(x) 打乱原数组的顺序,shuffle直接在原数组进行修改
- np.random.permutation(x) x可以为数组或者一个数,当为数组时,打乱原数组的顺序,不在原数组上进行,返回新的数组,不改变自身数组;当x为一个数时,则会随机排列np.arange(x)。
arr = np.array([[1,2,3],[4,3,2],[5,3,8]])
np.random.shuffle(arr) # shuffle洗牌
arr
![661d09af693611af96b4cd725305e778.png](https://i-blog.csdnimg.cn/blog_migrate/28710ff0e697abc8571a0dae25546089.png)
arr1 = np.array([[1,2,3],[4,3,2],[5,3,8]])
np.random.permutation(arr1) # permutation 随机排列数组
arr1
![214d1ee0b724eb7c38130131e82bbbe5.png](https://i-blog.csdnimg.cn/blog_migrate/ba7780b5b609ccff3cc031e3d73199c6.png)
np.random.permutation(10)
![42825f2e475b39a4942b90d8bee2ae14.png](https://i-blog.csdnimg.cn/blog_migrate/a011728ea99b050714c1b100aca310d8.png)
- df.take()
df.take参数:(indices, axis=0, convert=None, is_copy=True, **kwargs)
axis=0 纵向排序,axis=1横向排序,默认为0,大部分情况下都是纵向排序
与permutation联合使用,可实现随机采样功能
示例数据
df
![bcf742759c7c70f391f303329aebb813.png](https://i-blog.csdnimg.cn/blog_migrate/a2fbaa2625e319e56f7c8509f24b1468.png)
对行进行随机排序,按照行索引
permutation中的x,类似于range(5),只能取到0 1 2 3 4,因此在跟take联合使用时,x的大小要跟df的行数相一致
df.take(np.random.permutation(5),axis=0)
![12c5ec129a387fa1a855e472b8a01454.png](https://i-blog.csdnimg.cn/blog_migrate/b54126f8e4a2e116f01b6ecd4d21ee6f.png)
df.take(np.random.permutation(3),axis=1)
![06199f181f5101ae223c328f99d92fdb.png](https://i-blog.csdnimg.cn/blog_migrate/d2a08b7637d3c1ba8dc3b17dfefc6f2a.png)
6.4 替换
df.replace()
df.replace参数:(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad')
- to_palce: 被替换的对象
- value:替换成新的值
- inplace: True原值上修改,False复制出一份修改
- method {'pad', 'ffill', 'bfill', `None`}四种替换方式,默认是“pad”
单值替换
df.replace(1,10,inplace=True)
![d5b6b2dc6deb94c5a1b197001aa8e020.png](https://i-blog.csdnimg.cn/blog_migrate/4e2e02ad1c4e6a42d510aebda30801d2.png)
多值替换
1 使用字典
dic={10:"满分",5:"中等"}
df.replace(dic)
# 或者 使用列表
df.replace([10,5],["满分","中等"])
![e1c326abf1996e613964c55d1dc22276.png](https://i-blog.csdnimg.cn/blog_migrate/480a647a35d3b3e3ea0297c75e295c86.png)
注:DataFrame中无法使用method和limit参数
6.5 映射与运算
- map() 可以实现映射和充当运算工具,map()不是df的函数,而是Series的,因为它只针对某一列进行操作
- apply() 只可以作为运算工具
6.5.1 map()
使用map通过字段映射,新增一列
emp_dic = {"姓名":["张三","李四","王五"],"dep_id":[1,2,3]}
emp = pd.DataFrame(emp_dic)
# 映射关系表
dic = {"张三":"Hurry","李四":"Lily","王五":"Tom"}
emp['e_name'] = emp['姓名'].map(dic)
![5ddfd0074a583fa74654b3e7852cc722.png](https://i-blog.csdnimg.cn/blog_migrate/d64dfed3732474f137f735ad8b9f4c6d.png)
使用map作为运算工具
df["up_num"] = df["C"].map(lambda x:x*20)
![09508f8489a23040e1a07da8bcf1dcf9.png](https://i-blog.csdnimg.cn/blog_migrate/8f3c6de59dbeda11d76b59b4047ebc76.png)
map常跟匿名函数lambda一块使用,当然也可以使用普通函数
def complex(s):
return s*10
df["up_num1"] = df["C"].map(complex)
![8cffb454fc35b0503ecf27c10a42a178.png](https://i-blog.csdnimg.cn/blog_migrate/41312676fe288af23e58d6d210f5b291.png)
注意:并不是任何形式的函数都可以作为map的参数.只有当一个函数具有一个参数且有返回值,那么该函数才可以作为map的参数
6.5.2 apply()
只能当做运算工具,当运算量很大时,建议使用apply
df['up_num2'] = df['C'].apply(lambda x:x*5)
![3381ca5627ee846d97118e43b53d2b22.png](https://i-blog.csdnimg.cn/blog_migrate/4049a2c785f27b85e363d43134bb28e9.png)
7 DataFrame的分组聚合操作
7.1 分组聚合基本操作
- split : 先将数据按一个属性分组 (得到
DataFrameGroupby
/SeriesGroupby
) - apply : 对每一组数据进行操作 (取平均 取中值 取方差 或 自定义函数)
- combine: 将操作后的结果结合起来 (得到一个DataFrame 或 Series 或可视化图像)
使用groupby进行分组,groups查看分组情况
df.groupby参数:(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, observed=False, **kwargs)
实例数据
sale_data = pd.read_excel('./sale_data.xlsx') # 读取Excel文件
![25e2b4d975672d7e4c0c4f5de2286ba5.png](https://i-blog.csdnimg.cn/blog_migrate/fe19920a6dd630cf6a8791b29d20ceea.png)
需求1:计算各门店的销售数量
第一步:分组
sale_data.groupby(by="门店编码")
![8955e579cbd42a76b5983807814c143e.png](https://i-blog.csdnimg.cn/blog_migrate/4db898c2f1962f7e5fb4d129ce1cd139.png)
这是一个DataFrameGroupby,主要的功能能是允许你在不额外写循环的情况下, 快速对每一组数据进行操作。
第二步:聚合函数
sale_data.groupby(by="门店编码").sum()
如果不指定列,则默认对所有的列都进行聚合计算
![0d25285bc2cfe684850f01a1cc241122.png](https://i-blog.csdnimg.cn/blog_migrate/96821a65edbcaec6ff6f6f5fc1ecb134.png)
题目要求对销售数量,因此修改如下:
sale_data.groupby(by="门店编码")["销售数量"]
![71eb18e10c14148c38b2a65a9f24f58e.png](https://i-blog.csdnimg.cn/blog_migrate/b8ebdae85edff98ba7e441b4cae11319.png)
这是一个SeriesGroupBy对象,在不用循环的情况实现聚合计算
sale_data.groupby(by="门店编码")["销售数量"].sum()
![ed7e927a9bc866491608051a268d8a4b.png](https://i-blog.csdnimg.cn/blog_migrate/ec367b9d30b6f19f7f97ad155883e47e.png)
得到每个门店的销售数量总和是一个Series,聚合函数,还可以使用
std(标准差)、median(中位数)、min(最大值)、max(最小值)、mean(均值)
查看分组情况
sale_data.groupby(by="门店编码").groups
![9c8650b0150fea7147d65886d180794b.png](https://i-blog.csdnimg.cn/blog_migrate/882e552118b384a16435206a9f6b4776.jpeg)
需求2:计算每个产品的均价,并新增一列到sale_data?
mean_price = sale_data.groupby(by="产品编码")["单价"].mean()
mean_dic = mean_price.to_dict() # to_dict转换成字典形式
mean_dic
![389514146ad21bc72af3e570e6b5656a.png](https://i-blog.csdnimg.cn/blog_migrate/35f594710dfe1adc4b690fa61f72c47c.png)
sale_data["mean_price"] = sale_data["产品编码"].map(mean_dic)
![795b9cd123efd54aa69181d5b1b7617c.png](https://i-blog.csdnimg.cn/blog_migrate/b4b083892a27facbcdebfcda5c3a08c4.png)
7.2 分组聚合高级操作
使用groupby分组后,也可以使用transform和apply提供自定义函数实现更多的运算
sale_data.groupby(by="门店编码")["销售数量"].sum()
等价于 sale_data.groupby(by="门店编码")["销售数量"].apply(sum),然后对sum函数进行定义,这里的一些常用聚合函数,是pandas给定义好的,我们根据实际需要可以进行自定义
模拟mean函数实现对于不同产品的平均价格计算
# 定义求平均函数
def my_mean(s): # 使用apply传入的是分组后的,因此是一个Series
sum_num = 0
n=0
for i in s:
sum_num+=i
n+=1
return sum_num/n
# 实现分组聚合计算
sale_data.groupby(by="产品编码")["单价"].apply(my_mean)
![5d199b92c5426adca7965e02f224de36.png](https://i-blog.csdnimg.cn/blog_migrate/55dd7e902a90a49975840eef8331d44f.png)
# 使用transform返回的是原始数据每一行的值,对原数据结构并没有进行任何修改
sale_data.groupby(by="产品编码")["单价"].transform(my_mean)
![896200172be29836588bb542db21abdb.png](https://i-blog.csdnimg.cn/blog_migrate/b2c29dd76243f0e1c58afd491eba1cc6.png)
7.3 agg聚合操作
全称:aggregate
sale_data.agg({"销售数量":["sum","mean"],"单价":["sum","mean"]}) # aggregate
![1af6e1b7c1d68ac69f7571453484db49.png](https://i-blog.csdnimg.cn/blog_migrate/12d49e7dacf5bc1668e6931a558ddd7e.png)
8 DataFrame数据透视表与交叉表
8.1 DataFrame数据透视
这个数据透视表跟Excel中的数据透视功能是一样的,也是分组计算的一种方式,只能这种方式比groupby更加方便快捷,可操作性强,灵活好用。
df.pivot_table() 数据透视
参数:(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
- values: 对哪些列进行聚合计算,可以指定一列或多列
- index:根据哪一列进行行方向分组,也就是分组条件,这个是必须要有的,类似groupby中by,或者是Excel数透中的行标签
- columns: 根据哪一列进行列方向进行分组,类似于Excel数据透视的列标签
- aggfunc:聚合计算方式,也就是对应的聚合函数操作
示例还是上面的销售数据
需求1: 计算每个门店的总销售数量
sale_data.pivot_table(index="门店编码",values="销售数量",aggfunc="sum")
![d0663346c224b2e0e53b3c5811303418.png](https://i-blog.csdnimg.cn/blog_migrate/a0e116a2cd31a24620eba1d2632d41bd.png)
需求2:计算每个门店的每个产品的销售数量
sale_data.pivot_table(index="门店编码",columns="产品编码",values="销售数量",aggfunc="sum")
![42ceabd46801b5c1633c71701650ffb1.png](https://i-blog.csdnimg.cn/blog_migrate/3ba3944aecb23e389516e37df178649d.jpeg)
需求3: 计算2016年每月的每家门店的销售数量和平均单价
sale_data.pivot_table(index=["月份","门店编码"],values=["销售数量","单价"],aggfunc=["sum","mean"])
![46ed067cbea4d4626225856114398280.png](https://i-blog.csdnimg.cn/blog_migrate/62796134a39532a423914a94251783dd.png)
8.2 DataFrame交叉表
pd.crosstab() 主要用于分类数据计数,类似于列联表
参数;(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)
- index 交叉表的行标签
- columns 交叉表的列标签
pd.crosstab(sale_data["门店编码"],sale_data["产品编码"])
总结:
1 groupby对原DataFrame进行分组操作,返回DataFrameGroupby或SeriesGroupBy对象,在此基础上可直接进行采用已定义好的聚合函数进行计算。
2 使用apply和transform可以实现对于聚合操作的自定义,根据自己独有的规则设计函数,采用apply对已分组后的数据进行计算,返回的是分组后的计算结果。
3 apply和transform最大的不同在于,apply返回的分组后的列+分组后的计算结果,他已经改变了原始表的结构,而transfrom返回的是原始分组的列,以及对应的每一行的结果,保留了原始表的所有的。类似于SQL中的聚合函数和开窗函数的区别。
4 map是Series的方法,传入的是每个值,而apply既可以用于Series也可以用于DataFrame,并且用于DataFrame时传入的是一个Series,而用于Series时传入的是个值,transform用法与apply一致,只是返回的结果保持跟源数据结构一致。
5 aggregate用法比groupby更加简便。
pandas是python数据分析三剑客中非常重要 一员,所以写的内容比较细,比较多,希望能够对大家有所帮助。