Python数据分析学习笔记04:Pandas基础
在数据分析工作中,Pandas使用频率很高,一方面是因为Pandas提供的基础数据结构DataFrame与JSON契合度高,转换起来挺方便。另一方面,对于不太复杂的日常数据清理工作,通常用几句Pandas代码就可以对数据进行规整。
Pandas是基于NumPy构建的含有更高级数据结构和分析能力的工具包。NumPy中数据结构是围绕ndarray展开的,Pandas的核心数据结构是Series(序列——一维序列结构)和DataFrame(数据帧——二维表结构)。基于这两种数据结构,Pandas可以对数据进行导入、清洗、处理、统计和输出。
一、数据结构:Series和DataFrame
1、Series(序列——一维序列结构)
(1)概念:Series是个定长的字典序列。存储时相当于两个ndarray,这是与字典结构最大的不同,因为字典结构里,元素个数是不固定的。
(2)属性:index 与 value
index默认是从0开始的整数序列,当然也可以自己指定索引。
Series看起来像一种特殊的字典结构,因此我们也可以采用字典方式来创建Series。
Series元素的类型可以不一致,就像NumPy的数组,元素类型可以不同。
from pandas import Series
x1 = Series([100, 200, 300, 400])
x1
Out[3]:
0 100
1 200
2 300
3 400
dtype: int64
x2 = Series(data=[100, 200, 300, 400], index=['a', 'b', 'c', 'd'])
x2
Out[5]:
a 100
b 200
c 300
d 400
dtype: int64
x1[2], x2['c']
Out[6]: (300, 300)
x3 = Series({'a': 100, 'b': 200, 'c': 300, 'd': 400})
x3
Out[8]:
a 100
b 200
c 300
d 400
dtype: int64
x2 == x3
Out[9]:
a True
b True
c True
d True
dtype: bool
x4 = Series([1, 'Mike', 'male', 20])
x4
Out[11]:
0 1
1 Mike
2 male
3 20
dtype: object
import numpy as np
x5 = np.array([1, 'Mike', 'male', 20])
x5
Out[14]: array(['1', 'Mike', 'male', '20'], dtype='<U11')
x5[1]
Out[15]: 'Mike'
print(x5)
['1' 'Mike' 'male' '20']
print(x5)
['1' 'Mike' 'male' '20']
2、DataFrame(数据帧——二维表结构)
DataFrame包括行索引和列索引,可以将其看成是由相同索引的Series组成的字典类型。
行索引是默认的0、1、2、3、4,列索引是用户自定义的。当然行索引也可以自定义。
from pandas import DataFrame
data = {'Chinese': [89, 67, 89, 65, 84],
'Math': [78, 90, 63, 75, 80],
'English': [90, 67, 87, 60, 87]}
df1 = DataFrame(data)
df1
Out[4]:
Chinese Math English
0 89 78 90
1 67 90 67
2 89 63 87
3 65 75 60
4 84 80 87
df2 = DataFrame(data, index=['Mike', 'Alice', 'Frank', 'Brown', 'Smith'])
df2
Out[6]:
Chinese Math English
Mike 89 78 90
Alice 67 90 67
Frank 89 63 87
Brown 65 75 60
Smith 84 80 87
可以通过行索引取某一行的数据:
通过行索引与列索引获取某个元素值:
了解了Series与DataFrame这两个数据结构后,我们就可以从数据处理的流程角度来看它们的使用方法。
二、数据导入和输出
1、导入excel文件
2、导入csv文件
3、将数据帧导出成excel文件
当然,还可以将数据帧导出成各种格式的文件,比如csv、html、json等等。
三、数据清洗
1、删除数据帧中不必要的行或列
删除Brown所在行:
继续删掉Chinese那一列:
2、重命名列名
函数:rename(columns=new_names, inplace=True)
- 参数inplace设置True,直接在原数据帧上修改列名;
- 参数inplace设置为False,原数据帧列名不变,在返回的数据帧上修改列名。
将列名Math改为ShuXue,English改为YingYu:
可以看到,如果参数inplace设置为True,那么直接在原数据帧上修改列名。
如果参数inplace不设置,默认是False,那么原数据帧列名不变,返回的数据帧列名得到修改。
df2的列名还是ShuXue和YingYu,只有返回的数据帧df3列名改成了Math和English。
3、去掉重复的行
数据采集中可能存在重复的行,使用drop_duplicates()就能自动去掉重复的行。
注意,调用这个去重方法,不改变原数据帧,只是在返回的数据帧里去掉重复的行。
4、格式问题
(1)更改数据格式(类型)
使用astype函数来规范数据格式,比如将数据帧df2的ShuXue字段值改成str类型:
将df2的YingYu字段类型改成float64:
此时,再查看数据帧df2的内容:
有点奇怪,YingYu字段的值还是整型,没有变成浮点型。
import numpy as np
import pandas as pd
from pandas import DataFrame
data = {'Chinese': [89, 67, 89, 65, 84],
'Math': [78, 90, 63, 75, 80],
'English': [90, 67, 87, 60, 87]}
df1 = DataFrame(data)
df1
Out[6]:
Chinese Math English
0 89 78 90
1 67 90 67
2 89 63 87
3 65 75 60
4 84 80 87
df2 = DataFrame(data, index=['Mike', 'Alice', 'Frank', 'Brown', 'Smith'])
df2
Out[8]:
Chinese Math English
Mike 89 78 90
Alice 67 90 67
Frank 89 63 87
Brown 65 75 60
Smith 84 80 87
df2 = df2.drop(columns=['Chinese'])
df2
Out[10]:
Math English
Mike 78 90
Alice 90 67
Frank 63 87
Brown 75 60
Smith 80 87
df2 = df2.drop(index='Brown')
df2
Out[12]:
Math English
Mike 78 90
Alice 90 67
Frank 63 87
Smith 80 87
df2.rename(columns={'Math': 'ShuXue', 'English': 'YingYu'}, inplace=True)
df2
Out[14]:
ShuXue YingYu
Mike 78 90
Alice 90 67
Frank 63 87
Smith 80 87
col1 = df2['ShuXue'].astype(np.string_)
col2 = df2['YingYu'].astype(np.float64)
DataFrame(col1)
Out[17]:
ShuXue
Mike b'78'
Alice b'90'
Frank b'63'
Smith b'80'
DataFrame(col2)
Out[18]:
YingYu
Mike 90.0
Alice 67.0
Frank 87.0
Smith 87.0
# 将col1与col2横向拼接
pd.concat([col1, col2], axis=1)
Out[20]:
ShuXue YingYu
Mike b'78' 90.0
Alice b'90' 67.0
Frank b'63' 87.0
Smith b'80' 87.0
(2)大小写转换
有三个函数upper()、lower()、title()。
(3)数据间的空格
有时先将数据转换成str类型,是为了方便对数据进行操作,比如要删除数据间的空格,就可以使用strip函数。
也可以用strip函数来删除特定的字符:
5、查找空值
数据源可能存在有些字段是NaN的情况,如何查找空值呢?可以利用pandas的isnull函数来查找。
如果想知道哪一列存在空值,可以利用df.isnull().any()函数:
6、使用apply函数对数据进行清洗
apply函数是Pandas中自由度非常高的函数,使用频率也十分高。
(1)应用系统自带函数
(2)应用自定义函数
定义一个提分20%的函数:
将这个提分函数应用到Chinese科目上:
定义一个函数,添加一个新字段Score,计算三科成绩的加权平均值:
7、添加行和添加列
(1)添加新行:Green 89 89 85
(2)在Alice之后插入新行:Brian 56 63 90
(3)添加新列:Average
四、数据统计
在数据清洗后,我们就要对数据进行统计了。Pandas和NumPy一样,都有常用的统计函数,如果遇到空值NaN,会自动排除。
1、count()函数
2、describe()函数 —— 统计大礼包,对数据有个全面的了解
3、方差函数var()
4、中位数函数median()
五、数据表合并
两个数据表DataFrame合并要使用merge()函数,有下列5种形式:
1、基于指定列进行连接
2、inner内连接
inner内连接是merge函数的默认情况,基于公共键进行连接,因为df1与df2的公共键是name,其实就是基于name的连接:
3、left连接
left连接是以第一个DataFrame为主,第二个DataFrame为辅的连接。
4、right连接
right连接是以第二个DataFrame为主,第一个DataFrame为辅的连接。
5、outer外连接
外连接相当于两个DataFrame求并集。
如何查询成绩在90分以上的记录?
如何查询成绩在80分与90分之间的记录?
六、如何用SQL方式打开Pandas
Pandas的DataFrame数据类型可以让我们像处理数据表一样进行操作,比如数据表的增删改查,都可以用Pandas工具来完成。不过也有很多人记不住这些Pandas命令,而希望采用自己更加熟练的SQL语句来对数据表进行操作。
利用pandasql工具可以采用SQL语句操作数据表。pandasql主要的函数sqldf,接收两个参数:SQL查询语句和一组环境变量globals()或locals()。这样我们就可以在Python里直接用SQL语句操作DataFrame了。
1、安装pandasql工具包
2、查询案例演示
(1)查询姓名为Howard的记录
(2)查询语文成绩在80与90之间的记录
在定义pysqldf时候采用了lamda函数,也就是匿名函数,对于sql语句进行处理。
不用pandasql,也可以直接利用pandas语句完成同样的查询任务:
(3)将Howard的语文成绩改成99
(4)删除姓名为Howard的记录
七、总结
和NumPy一样,Pandas有两个非常重要的数据结构:Series和DataFrame。
使用Pandas可以直接从csv或xslx等文件导入数据,以及最终输出到不同类型的文件中,比如csv或excel文件。
重点学习了数据清洗的操作,以及Pandas提供的统计函数,尤其大家要记住的是统计大礼包函数describe()。
学习了如何利用merge函数将两个数据表合并,并学习了5种不同的连接方式。
学习了利用pandasql工具在Pandas里采用sql语句对数据表进行操作。
Pandas包与NumPy库配合使用可以发挥巨大的威力,正是有了Pandas(潘大师)工具,Python做数据挖掘才有优势。
练习题
利用下表创建DataFrame,进行数据清洗。同时新增一列“总和”计算每个人三科成绩之和。
# 数据清洗
import pandas as pd
from pandas import DataFrame
df = pd.read_excel('e:/excelfiles/test2.xlsx')
print("原表:")
print(df)
# 1. 删除有NaN值的行
cols = []
nullcols = df.isnull().any()
for i in range(len(nullcols)):
if nullcols[i] == True:
cols.append(nullcols.index[i])
nulltable = df.isnull()
for i in range(len(cols)):
nullindex = nulltable[nulltable[cols[i]] == True].index[0]
df = df.drop(index = nullindex)
print("删除有NaN的行:")
print(df)
# 2. 删除重复的行
df = df.drop_duplicates()
print("删除重复的行:")
print(df)
# 3. 添加总分字段,计算总分
df['总分'] = (df['语文'] + df['英语'] + df['数学']) / 3
print("添加总分字段:")
print(df)
运行结果:
原表:
姓名 语文 英语 数学
0 张飞 66.0 65.0 NaN
1 关羽 95.0 85.0 98.0
2 赵云 95.0 92.0 96.0
3 黄忠 90.0 88.0 77.0
4 典韦 80.0 90.0 90.0
5 典韦 80.0 90.0 90.0
6 马超 NaN 89.0 74.0
7 曹洪 89.0 78.0 96.0
8 张郃 80.0 67.0 86.0
9 徐晃 85.0 NaN 56.0
删除有NaN的行:
姓名 语文 英语 数学
1 关羽 95.0 85.0 98.0
2 赵云 95.0 92.0 96.0
3 黄忠 90.0 88.0 77.0
4 典韦 80.0 90.0 90.0
5 典韦 80.0 90.0 90.0
7 曹洪 89.0 78.0 96.0
8 张郃 80.0 67.0 86.0
删除重复的行:
姓名 语文 英语 数学
1 关羽 95.0 85.0 98.0
2 赵云 95.0 92.0 96.0
3 黄忠 90.0 88.0 77.0
4 典韦 80.0 90.0 90.0
7 曹洪 89.0 78.0 96.0
8 张郃 80.0 67.0 86.0
添加总分字段:
姓名 语文 英语 数学 总分
1 关羽 95.0 85.0 98.0 92.666667
2 赵云 95.0 92.0 96.0 94.333333
3 黄忠 90.0 88.0 77.0 85.000000
4 典韦 80.0 90.0 90.0 86.666667
7 曹洪 89.0 78.0 96.0 87.666667
8 张郃 80.0 67.0 86.0 77.666667
删除有NaN的行,算法可以简化一点:
删除有NaN的行,显得太简单粗暴,可以采用比较温和的均值填充法。
运行结果如下:
原表:
姓名 语文 英语 数学
0 张飞 66.0 65.0 NaN
1 关羽 95.0 85.0 98.0
2 赵云 95.0 92.0 96.0
3 黄忠 90.0 88.0 77.0
4 典韦 80.0 90.0 90.0
5 典韦 80.0 90.0 90.0
6 马超 NaN 89.0 74.0
7 曹洪 89.0 78.0 96.0
8 张郃 80.0 67.0 86.0
9 徐晃 85.0 NaN 56.0
用列均值填充NaN值:
姓名 语文 英语 数学
0 张飞 66.0 65.0 84.8
1 关羽 95.0 85.0 98.0
2 赵云 95.0 92.0 96.0
3 黄忠 90.0 88.0 77.0
4 典韦 80.0 90.0 90.0
5 典韦 80.0 90.0 90.0
6 马超 84.4 89.0 74.0
7 曹洪 89.0 78.0 96.0
8 张郃 80.0 67.0 86.0
9 徐晃 85.0 82.7 56.0
删除重复的行:
姓名 语文 英语 数学
0 张飞 66.0 65.0 84.8
1 关羽 95.0 85.0 98.0
2 赵云 95.0 92.0 96.0
3 黄忠 90.0 88.0 77.0
4 典韦 80.0 90.0 90.0
6 马超 84.4 89.0 74.0
7 曹洪 89.0 78.0 96.0
8 张郃 80.0 67.0 86.0
9 徐晃 85.0 82.7 56.0
添加总分字段:
姓名 语文 英语 数学 总分
0 张飞 66.0 65.0 84.8 71.933333
1 关羽 95.0 85.0 98.0 92.666667
2 赵云 95.0 92.0 96.0 94.333333
3 黄忠 90.0 88.0 77.0 85.000000
4 典韦 80.0 90.0 90.0 86.666667
6 马超 84.4 89.0 74.0 82.466667
7 曹洪 89.0 78.0 96.0 87.666667
8 张郃 80.0 67.0 86.0 77.666667
9 徐晃 85.0 82.7 56.0 74.566667