前言
python有个很好用的数据分析库pandas,前段时间做了个数据挖掘的比赛,里面数据分析的部分,是用pandas来实现的,今天借助自己实践的经验,来总结一下pandas常用的数据分析方法。
1,创建数据表
pandas创建的数据是DataFrame格式的数据,有一些创建方法,其中有细微的差别,我们来实践一个简洁常用的方法,此处创建的数据作为后续数据分析的data。
创建三个数据表,分别为年级信息表:grade,一年级成绩表:g_one_score,二年级成绩表:g_two_score。
#先导入需要的库
import numpy as np
import pandas as pd
import os
os.chdir("D:/知乎图/pandas_data/")#将工作路径转为此路径
grade=pd.DataFrame({"年级":["一","一","二","二"],"班级":["一班","二班","一班","二班"],
"班级代号":[11,12,21,22],"班主任":["大绿","大红","大白","大紫"],"人数":[2,3,3,2]})
g_one_score=pd.DataFrame({"班级代号":[11,11,12,12,12],"姓名":["小红","小绿","小蓝","小紫",
"小粉"],"数学":[97,96,90,98,99],"语文":[91,91,92,93,89],"英语":[79,76,80,97,100]})
g_two_score=pd.DataFrame({"班级代号":[21,21,21,22,22],"姓名":["小黑","小白","小橙",
"小青","小黄"],"数学":[100,87,86,90,88],"语文":[92,87,96,93,89],"英语":[69,np.nan,92,90,79]})
![389d2a1b39ac3758c08b704ae58faed1.png](https://i-blog.csdnimg.cn/blog_migrate/a31dcea51d0f47e7724ac0430811f105.png)
![eca321b0ecad126c33c3ab72804272a5.png](https://i-blog.csdnimg.cn/blog_migrate/3e9cb2577af27155868168706c35c2a3.png)
![612912040ceef20b3c31a9ca58be151d.png](https://i-blog.csdnimg.cn/blog_migrate/f90ef06b6fa7a7aec336e04adb901968.png)
这里数据有点简陋,能说明问题即可。在表g_two_score表里有一个空值NaN,代表这个同学这门课缺考。
2,保存数据
我们生成的数据可保存为csv,或excel文件,方便以后调用。
##参数index设置为False,表示为不将index存入,不然下次调用,会多出一列。
grade.to_csv("grade.csv",index=False)
g_one_score.to_csv("g_one_score.csv",index=False)
g_two_score.to_csv("g_two_score.csv",index=False)
此时,你的路径里多出以下三个文件。
![09788f94d68d440aabd9f4b7fe679568.png](https://i-blog.csdnimg.cn/blog_migrate/e99d0baecbe5873ae29f3a6b023ce88a.png)
3,读取数据
#读取数据
grade=pd.read_csv("grade.csv")
g_one_score=pd.read_csv("g_one_score.csv")
g_two_score=pd.read_csv("g_two_score.csv")
好了,兜了一圈,把数据读出来了,以上看似多余的操作,主要也是为了讲解pandas的用法,因为有时候,你只有csv文件,因此你需要读取操作,有时候,你需要存储操作。
4,查看和提取数据
4.1, 一般读取数据后,首先查看数据的大小,即shape。
print("grade:",grade.shape)
print("n")
print("g_one_score:",g_one_score.shape)
print("n")
print("g_two_score:",g_two_score.shape)
![2070b534fc3aad4c01299fcbbff2825a.png](https://i-blog.csdnimg.cn/blog_migrate/bb2cb2d3e1efdb9cb3c370d28f23213b.png)
4.2, 查看每列的空缺值个数
g_two_score.isnull()#isnull()函数查看空缺值
![675c05654c9fdb9e84084feb5e70bd96.png](https://i-blog.csdnimg.cn/blog_migrate/df00e431b114236f31e86ea6a3dbceee.png)
有时候是查看数据每列的空缺值个数,用来判断每个特征值是否有效,空缺值太大,在做数据挖掘时,此特征会丢掉,空缺值少,会想办法补上。
g_two_score.isnull().sum()
![0c85f09b6ac5ce297ca8d1acc63d65bc.png](https://i-blog.csdnimg.cn/blog_migrate/099422d26da2b9c7b2e278d301b2a07e.png)
这里把补空缺值的方法讲了吧,思路有几种:①补同列上一行的值,②补同列下一行的值,③补指定的值。具体怎么填补,要在理解数据的基础上进行操作。使用的函数为:fillna()函数。
![39dd03080a2ebbab9d482bf65f517a9c.png](https://i-blog.csdnimg.cn/blog_migrate/8d1783e9f67cca22f916438a5425f722.jpeg)
#我们,这里认为缺考成绩为0,因此用指定值0来填充。
g_two_score.fillna(0,inplace=True)
g_two_score
![451b0dc7c65d998d67328af344c1998f.png](https://i-blog.csdnimg.cn/blog_migrate/3ec91a198669eabb1074d9778bb886fb.png)
还有一个操作是填补此列的空缺值,将指定值参数赋值为此列的均值即可,那需要先求出此列均值。具体怎么做我们后面讲描述性统计方法时再说。
4.3, 查看数据表的值.values
#如果我们需要将数据的值提取出来,转化为二维数组或者矩阵形式,可这么做
g_two_score_values=g_two_score.values
g_two_score_values
![0e2134fb13cfd904d20876094599dcd3.png](https://i-blog.csdnimg.cn/blog_migrate/9cd1cffdd3f5e88d4b17b0b62bbd194c.png)
4.4, 查看数据前五行,或后五行数据
g_two_score.head()#默认查看前五行,也可填入你想查看的行数。
![9cabe3943ab0f99ae3ddd32ac538699b.png](https://i-blog.csdnimg.cn/blog_migrate/f6e15bf72dd88f4560a5bdb62391dcc5.png)
g_two_score.tail(3)#默认查看后5行,也可填入想查看的行数
![fd10bca047fab8210917a56eb02682f7.png](https://i-blog.csdnimg.cn/blog_migrate/b0282c2465f825b7bc37cc44cbf7daf4.png)
4.5, 查看数据的列名称,这个在做数据处理时,会常用
g_two_score.columns
Index(['班级代号', '姓名', '数学', '语文', '英语'], dtype='object')
4.6, 使用.loc[ ],.iloc[ ]进行数据提取查看。
g_two_score.iloc[0:3]#提取0,1,2,行数据,索引的方式与数组一样。
![7aaad66e993a728c086f1d33974342a6.png](https://i-blog.csdnimg.cn/blog_migrate/c887e6bf91b941377aece4fd10552298.png)
如果想只查看某些列的前三行数据可以这么做
g_two_score.iloc[0:3,1:3]
![3fe98b10ce7ce65cf1a698bc75458742.png](https://i-blog.csdnimg.cn/blog_migrate/c14faf730dd1ef37341bd5793b872d19.png)
但是有时候,我们的数据很大,我们不能很方便得到想要查看列的索引,但是我们知道列名称,可以使用loc来操作。
g_two_score.loc[0:3,["姓名","语文"]]#等价于g_two_score.iloc[0:3,[1,3]]
![4cd912ee57a91a78fcf76e0667b68ae7.png](https://i-blog.csdnimg.cn/blog_migrate/77b920b65e528315173636aec1fc4f25.png)
也可以直接提取指定列的信息
g_two_score["语文"]#得到的是一个Series
0 92
1 87
2 96
3 93
4 89
Name: 语文, dtype: int64
或者,我们想查看特定条件的行数据,比如提取小白和小橙的成绩信息,可以这么做
g_two_score["姓名"].isin(["小白","小橙"])#使用isin()函数判断,提取的行数
0 False
1 True
2 True
3 False
4 False
Name: 姓名, dtype: bool
g_two_score.loc[g_two_score["姓名"].isin(["小白","小橙"])]
![b32875c780b379e77e7bde88695dcc28.png](https://i-blog.csdnimg.cn/blog_migrate/7fe25071872e96d85f399c5a6287fac6.png)
再或者,我们想查看其他特定条件的行数据,比如提取二班信息
- 数学成绩大于88的同学信息。
- 数学成绩大于88并且英语成绩大于85的同学信息。
- 数学成绩大于88或者语文成绩大于90的同学的信息。
- 数学成绩等于100的同学信息。
- 除了小白的信息提取出来。(有两种方式)
代码如下
g_two_score.loc[g_two_score["数学"]>88]
g_two_score.loc[(g_two_score["数学"]>88)&(g_two_score["英语"]>85)]
g_two_score.loc[(g_two_score["数学"]>88)|(g_two_score["语文"]>90)]
g_two_score.loc[g_two_score["数学"]==100]
g_two_score.loc[g_two_score["姓名"]!="小白"]
g_two_score.loc[~(g_two_score["姓名"]=="小白")]#取反操作,也可实现
###围观
可以不用.loc 也可实现此操作
g_two_score[g_two_score["数学"]>88]
g_two_score[(g_two_score["数学"]>88)&(g_two_score["英语"]>85)]
g_two_score[(g_two_score["数学"]>88)|(g_two_score["语文"]>90)]
g_two_score[g_two_score["数学"]==100]
g_two_score[g_two_score["姓名"]!="小白"]
g_two_score[~(g_two_score["姓名"]=="小白")]#取反操作,也可实现
5,删除数据
使用drop()函数
![070b0a71eddcc9be4c679173c2d1e92b.png](https://i-blog.csdnimg.cn/blog_migrate/40a65d1fdf8d58f7100ebe517afd264d.jpeg)
例子如下:
g_two_score.drop("英语",axis=1)##删除“英语”这一列
g_two_score.drop(columns=["数学"],index=[0,1])
#删除数学这一列,和0,1行,这里,我们没有设index的名称,所以是自动生成的0,1,2,3,4
还有一种间接实现“删除”的方式,加双引号,只是不是真正的删除操作,就是前面讲过的取反操作,当你的数据很大,很多行,而你只想删除一小部分满足某条件的行,此时用drop实现不了,那我们可以提取,不满足这些条件的行,间接得到“删除”后的数据。
如:我们想提取删除语文成绩小于90,或者英语成绩小于80的数据
g_two_score[~((g_two_score["语文"]<90)|(g_two_score["英语"]<80))]
![d51dce28ff5a9a0fe7e2b36c2e6c3a55.png](https://i-blog.csdnimg.cn/blog_migrate/afbf3345b3b9e506766e96650b47f0e6.png)
当然,如果你知道具体的行标,也可用drop()来做,要学会灵活应用。
6,描述性统计方法
有时候,我们需要知道数据的一些,统计信息:均值,最大值,最小值,总和。当然,这些只能在数值型数据上进行操作。
函数describe()能统计各列诸多统计值
g_two_score.describe()#count非空元素的数目
![e55a9cfc0daf769866308285c8277f61.png](https://i-blog.csdnimg.cn/blog_migrate/eb8ee6f0581b3207cc9afc6224214fb8.jpeg)
这里班级代号这一列并没有用,只不过,当时输入的也是数值。
count:非空元素个数。mean:均值。std:标准差。min:最小值。25%:四分之一分位数。max:最大值。
也可以单个求某列,或某些列的特定统计信息
print(g_two_score.quantile(0.25))#25%分位数
print("n")#换行
print(g_two_score["英语"].mean())
print("n")#换行
print(g_two_score[["语文","英语"]].min())
班级代号 21.0
数学 87.0
语文 89.0
英语 69.0
Name: 0.25, dtype: float64
66.0
语文 87.0
英语 0.0
dtype: float64
与describe()得到的结果一致,没有错误
还记得之前补空缺值时的操作吗,我们说可以补均值,因为有时候,补均值会比较合理,实现方法如下:
g_two_score["英语"].fillna(g_two_score["英语"].mean())
0 69.0
1 82.5
2 92.0
3 90.0
4 79.0
Name: 英语, dtype: float64
如果加上参数inplace=True,我们的原数据就填补完成了,不含空值,不过这里需指定单个的列。
7,合并
7.1,merge函数
用法
DataFrame1.merge(DataFrame2, how=‘inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=(’_x’, ‘_y’))
或
pd.merge(DataFrame1,DataFrame2, how=‘inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=(’_x’, ‘_y’))
参数
- how 可选“inner”,“outer”,“left”,“right”,与sql里的join一样,内连接,外连接,左外连接,右外连接。
- on 可选两个表连接时依据的字段名,若连接的依靠的字段在两个表中名字一致,则使用此参数,=“字段名”,若依靠的连接字段在连个表中名字不同,则需使用left_on和right_on分别来指定两个表中的字段名。
- left_on,左表连接的字段名。
- right_on 右表连接的字段名。
- right_index 若使用右表的行索引名来连接,则将此参数赋值为True。
- left_index 若使用坐标的行索引来连接,则将此参数赋值为True。在需要将两个表直接横向合并一起时,例如,我们的grade表被统计成了两个表,一个表上只有信息“年级”“班级”“班级代号”另一个表上的信息为“班主任”“人数”,两个表需要是对应的,这样可将两个index参数赋值为True,将两个表合并为一个更加完整的表。
- sort合并后的表是否排序
- suffixes此参数是当两个表中的字段名相同时,自动将字段名后面加_x,_y等。
举例来看,比如我们想知道二班成绩表里的每位同学所属班级,班主任等grade表里的信息,我们的想法自然是将两个表连接起来。连接的依据字段为班级代号,即把班级代号相同的行连接起来。
grade.merge(g_two_score,on="班级代号",how="inner")
![dd949b8e97cf0b7b3a71e71e679bf6fc.png](https://i-blog.csdnimg.cn/blog_migrate/fd39c43a5a7672e01518c4412127471d.png)
如果懂sql的同学,对于这部分的理解会比较容易,刚接触的同学理解会有一点困难,我再多写一句,这里的连接,你可以这么想,连接的过程可以想象为,笛卡尔积,即左表的每一行会与右表的每一行配对,然后依据on将所选字段对应相等的联结行留下来,其他的不符合的删掉,就是最终的结果。
这里说成联结比较专业,我一般写成连接了。
如果两个表里联结的字段名不同呢,比如在g_two_score里的“班级代号”是“班级代码”呢,怎么做,该left_on和right_on上场了。
#使用rename函数将g_two_score里的字段名“班级代号”重命名为“班级代码”,赋值给一个新表
g_two_copy=g_two_score.rename(columns={"班级代号":"班级代码"})
#将grade表和g_two_score表依据左表的“班级代号”和右表的“班级代码”来连接,代码如下
grade.merge(g_two_copy,left_on="班级代号",right_on="班级代码",how="inner")
![41d81f2231f3cde9ae357f07030809f1.png](https://i-blog.csdnimg.cn/blog_migrate/8afb7a461fc745d3942b58a7b97c54af.png)
现在试试左外联结on=“left”,左外连接是将左表里多余的没有关联的行留下
pd.merge(grade,g_two_score,on="班级代号",how="left")
![f7a9c249aabcc90831108e4ecfe7b37f.png](https://i-blog.csdnimg.cn/blog_migrate/f4f78e775e85365ffff5e207b3be3a22.png)
可以看到班级代号为11,12的没有关联的行,但是溜了下来,右外联结“right”,是将右表中没有关联的行留下来,全外连接“outer”是将两个表中没有关联的行全留下来。
7.2,concat
用法
pd.concat([DataFrame1,DataFrame2],axis=0,join="outer",join_axes=None,ignore_index=False,keys=None,sort=True)
参数
- axis 取值0或1,0代表竖向合并,1代表横行合并,默认竖向
- join 取并集“outer”or 取交集“inner”
- join_axes 默认为None,取并集时使用,合并后在非合并方向上选取某个表的有的字段显示。join_axes=[DataFrame.columns]
- ignore_index 默认False,合并方向是否忽略原行/列名称,而采用系统默认,即从0开始。
- keys 默认为None,若有值,则会在外围添加一层标签,指定,某些行/列来自于哪个表。
- sort,是否排序,默认为True,非合并方向的标签是否排序
举个例子来说明什么情况下使用concat
例1:xx水果店有三个员工,一周轮流上班,每天的员工需记录每天每种水果的销量,前三天小明值班,但她只记录了“苹果”“香蕉”“橘子”“火龙果”的销量;星期四,五,小红值班,她只记录了“苹果”“香蕉”“芒果”“猕猴桃”的销量;星期六,日,小海值班,他只记录了“橘子”“火龙果”“芒果”“猕猴桃”的销量。这三个员工不称职啊,哈哈,我们为了能说明问题,瞎编的哈。
###这也是构造数据的另一种方法。
d1=pd.DataFrame(np.ones((3,4)),columns=["苹果","香蕉","橘子","火龙果"],index=["星期一","星期二","星期三"])
d2=pd.DataFrame(2*np.ones((2,4)),columns=["苹果","香蕉","芒果","猕猴桃"],index=["星期四","星期五"])
d3=pd.DataFrame(3*np.ones((2,4)),columns=["橘子","火龙果","芒果","猕猴桃"],index=["星期六","星期日"])
![b9ad423aa8de94f8a1007cd6cfdd72f2.png](https://i-blog.csdnimg.cn/blog_migrate/564d759fd8110885d35678dc27dcacb2.png)
![5f3029b5a7e1e0476c7674c5e37542a3.png](https://i-blog.csdnimg.cn/blog_migrate/39bc65f6e49e735ba1de4ee9e3764138.png)
![5e26aa93256057f4fc9d9e9919f3b878.png](https://i-blog.csdnimg.cn/blog_migrate/8a6df059e0e50dd821cc9eac60cc1a86.png)
##我们跟前两个表来看一下,前五天的销售情况,主要看一下join的两种不同的取值差别
pd.concat([d1,d2],join="outer",axis=0,sort=False)##并集,没有数据按空值处理
pd.concat([d1,d2],join="inner",axis=0,sort=False)##交集
![564d737a9f5622b68259507a45e458f3.png](https://i-blog.csdnimg.cn/blog_migrate/32a5f1e5b67d78b8e36db9d4976446b9.png)
![379e1c759facca4b91dd27c5994548fb.png](https://i-blog.csdnimg.cn/blog_migrate/de67af6260bb22f8bf384af43976b1e2.png)
###join_axes
pd.concat([d1,d2],join="outer",axis=0,join_axes=[d1.columns],sort=False)#只显示d1含有的水果名
![0f95f0d2617bea4bba4ecdc04ed16ff4.png](https://i-blog.csdnimg.cn/blog_migrate/28e00b2e175863a8730d232236b69ec4.png)
#忽略原有行标,默认系统生成。
pd.concat([d1,d2],join="outer",axis=0,join_axes=[d1.columns],ignore_index=True,sort=False)
![e9f27c511c078188bf56388f0c7f669e.png](https://i-blog.csdnimg.cn/blog_migrate/8c192a982ae6a4701b70e2313d0d5a57.png)
###使用keys
pd.concat([d1,d2],join="outer",axis=0,join_axes=[d1.columns],keys=["x","y"],sort=False)
![7161bbb96d2edc6b7cc435a34389b86a.png](https://i-blog.csdnimg.cn/blog_migrate/bf650465283db26c76292a8650ae9277.png)
关于axis=1的方向的合并,我就不举例子了,如果碰到,这样的问题:水果店有两个员工,一个人记录其中几个水果的销量,我们需要合并记录这一周两个员工记录的水果销量。这时候需要横向合并,具体问题具体来分析怎么合并。
7.3,append
这是一个最简单的合并函数,只能竖向合并
用法
DataFrame1.append(DataFrame2,ignore_index=False
)
等价于pd.concat([DataFrame1,DataFrame2])
还记不记得我们还有一个表:g_one_score,一班同学的成绩信息表,我们现在想将一般和二班同学的成绩合并在一起,可以这么做。
g_one_score.append(g_two_score,ignore_index=True)##ignore_index参数跟concat里的一样
![cc8d99c1484f7ef58b99a1a2dd98d127.png](https://i-blog.csdnimg.cn/blog_migrate/55db81da976d8e21e1ac58c7d02bab19.png)
8,groupby函数与agg函数
8.1,grouby()
groupby()函数的作用与sql里的group by一样,按某列或几列的值实行分组。
按某一列对表中的某一列进行分组计算
##计算每个班的数学均值
g_two_score["数学"].groupby(g_two_score["班级代号"]).mean()
班级代号
21 91
22 89
Name: 数学, dtype: int64
按某一列对表中的多列进行分组计算
g_two_score[["数学","语文"]].groupby(g_two_score["班级代号"]).sum()
![d552d7e36ecf8dd03dc51f0c45c0a4c1.png](https://i-blog.csdnimg.cn/blog_migrate/f97804d6861cada1072ad7556dffaae1.png)
注:groupby里面的依据分组字段必须写成 g_two_score["班级代号"] 原因为需要分组的字段里不含有“班级代号”,如果写成这样
g_two_score[["数学","语文"]].groupby(["班级代号"]).sum()
###会报错,原因找不到字段“班级代号”
下面这样是可以的,这也是易出现的小错误的地方
g_two_score[["数学","语文","班级代号"]].groupby(["班级代号"]).count()
![b52a7fba7031b7c5cc9de0768ccd72d9.png](https://i-blog.csdnimg.cn/blog_migrate/8341a63fc973df218ea5d189a916fc53.png)
按多列对表中的多列进行分组计算
#先按“年级”再在每个年级里按班级分组,最后计算每个小组的个数
grade[["班主任","人数"]].groupby([grade["年级"],grade["班级"]]).count()
![a80f4bb3527358f6a4981652b623a3d3.png](https://i-blog.csdnimg.cn/blog_migrate/6c9c65fd8033a2ba42787938fe8bc914.png)
有时候是对整个表按照某一列或多列进行分组
grade.groupby([grade["年级"]]).count()
![990a812d1d3c936710c6610892d9f20f.png](https://i-blog.csdnimg.cn/blog_migrate/5444488f5bb11367f9ad8bb459369d03.png)
如果整个表进行分组后,只想看某一列的数据
grade.groupby([grade["年级"]])["人数"].count()
年级
一 2
二 2
Name: 人数, dtype: int64
注:上面我们看到数据分组后会跟着一个统计计算,我们来列一下有哪些统计计算。
![443401d008c34bd9306cc8fc72de9980.png](https://i-blog.csdnimg.cn/blog_migrate/418c027a6465a7c9043ff5a152173870.jpeg)
还有些统计性分析的函数,会在做数据分析的时候用到,我们在这里提一下
#计算两个字段的相关性
g_two_score["数学"].corr(g_two_score["英语"])
#计算这个数据表的相关性,即任意两个字段的相关性
g_two_score.corr()
8.2,agg()
groupby函数经常与agg函数一起使用,我们看一下,agg是怎么用的。
对所有列应用一个相同的统计计算
gg=g_two_score.groupby(["班级代号"])##先分组
gg.agg("mean")###后聚合计算
![1eb27882777f103d5bb853debd28b0be.png](https://i-blog.csdnimg.cn/blog_migrate/d84663bf1413b1db8ad3feb2e9797f61.png)
这个结果与
g_two_score.groupby(["班级代号"]).mean()
结果相同。
对所有列应用相同的多种统计计算
当我们想对分组后的数据进行多种统计计算时,比如:mean,std一起时,agg的有点就显现出来了。
gg=g_two_score.groupby(["班级代号"])
gg.agg(["mean","std"])#多种统计函数使用列表
![527dabc94a27078889ca261200534d03.png](https://i-blog.csdnimg.cn/blog_migrate/f481519c473a9a7a156a5533c76077a8.png)
对所有列应用不同的多种统计计算
也可以对不同分组后的字段进行不同的统计计算,我们使用字典来传入。
gg=g_two_score.groupby(["班级代号"])
gg.agg({"数学":["mean","sum"],"语文":["std","sum"],"英语":"max"})
![58324cbb0b97bb414ae1e98220e377fc.png](https://i-blog.csdnimg.cn/blog_migrate/c7b774acab42b1a7abc092a221ff6448.png)
应用自定义函数
除此之外,还可以传入自己设置的函数。比如设置一个计算极值的函数。
def r_func(arr):#极差
return arr.max()-arr.min()
gg=g_two_score.groupby(["班级代号"])
gg.agg({"数学":["mean","sum"],"语文":["std","sum"],"英语":["max",r_func]})
![76d8938c5218b4fce99ca764fe1a66e9.png](https://i-blog.csdnimg.cn/blog_migrate/4a876d55dabe8a7cf8bc5dc9c45da1dc.png)
感谢参考到的几篇文章!
pandas 菜鸟教程_python_夭夜的博客-CSDN博客blog.csdn.net![47c150551014428ad0c410b8c07e34e1.png](https://i-blog.csdnimg.cn/blog_migrate/5481e3cee1abea183eab1e74d5e67d50.jpeg)