今天我来给你介绍Python的另一个工具Pandas。
在数据分析工作中,Pandas的使用频率是很高的,一方面是因为Pandas提供的基础数据结构DataFrame与json的契合度很高,转换起来就很方便。另一方面,如果我们日常的数据清理工作不是很复杂的话,你通常用几句Pandas代码就可以对数据进行规整。
Pandas可以说是基于 NumPy 构建的含有更高级数据结构和分析能力的工具包。在NumPy中数据结构是围绕ndarray展开的,那么在Pandas中的核心数据结构是什么呢?
下面主要给你讲下Series和 DataFrame这两个核心数据结构,他们分别代表着一维的序列和二维的表结构。基于这两种数据结构,Pandas可以对数据进行导入、清洗、处理、统计和输出。
Series是个定长的字典序列。说是定长是因为在存储的时候,相当于两个ndarray,这也是和字典结构最大的不同。因为在字典的结构里,元素的个数是不固定的。
Series有两个基本属性:index 和 values。在Series结构中,index默认是0,1,2,……递增的整数序列,当然我们也可以自己来指定索引,比如index=[‘a’, ‘b’, ‘c’, ‘d’]。
import pandas as pd from pandas import Series, DataFrame x1 = Series([1,2,3,4]) x2 = Series(data=[1,2,3,4], index=['a', 'b', 'c', 'd']) print x1 print x2
1234567 | import pandas as pdfrom pandas import Series, DataFramex1 = Series([1,2,3,4])x2 = Series(data=[1,2,3,4], index=['a', 'b', 'c', 'd'])print x1print x2 |
---|
运行结果:
0 1 1 2 2 3 3 4 dtype: int64 a 1 b 2 c 3 d 4 dtype: int64
1234567891011 | 0 11 22 33 4dtype: int64a 1b 2c 3d 4dtype: int64 |
---|
这个例子中,x1中的index采用的是默认值,x2中index进行了指定。我们也可以采用字典的方式来创建Series,比如:
d = {'a':1, 'b':2, 'c':3, 'd':4} x3 = Series(d) print x3
1234 | d = {'a':1, 'b':2, 'c':3, 'd':4}x3 = Series(d)print x3 |
---|
运行结果:
a 1 b 2 c 3 d 4 dtype: int64
123456 | a 1b 2c 3d 4dtype: int64 |
---|
DataFrame类型数据结构类似数据库表。
它包括了行索引和列索引,我们可以将DataFrame 看成是由相同索引的Series组成的字典类型。
我们虚构一个王者荣耀考试的场景,想要输出几位英雄的考试成绩:
import pandas as pd from pandas import Series, DataFrame data = {'Chinese': [66, 95, 93, 90,80],'English': [65, 85, 92, 88, 90],'Math': [30, 98, 96, 77, 90]} df1= DataFrame(data) df2 = DataFrame(data, index=['ZhangFei', 'GuanYu', 'ZhaoYun', 'HuangZhong', 'DianWei'], columns=['English', 'Math', 'Chinese']) print df1 print df2
12345678 | import pandas as pdfrom pandas import Series, DataFramedata = {'Chinese': [66, 95, 93, 90,80],'English': [65, 85, 92, 88, 90],'Math': [30, 98, 96, 77, 90]}df1= DataFrame(data)df2 = DataFrame(data, index=['ZhangFei', 'GuanYu', 'ZhaoYun', 'HuangZhong', 'DianWei'], columns=['English', 'Math', 'Chinese'])print df1print df2 |
---|
在后面的案例中,我一般会用df, df1, df2这些作为DataFrame数据类型的变量名,我们以例子中的df2为例,列索引是[‘English’, ‘Math’, ‘Chinese’],行索引是[‘ZhangFei’, ‘GuanYu’, ‘ZhaoYun’, ‘HuangZhong’, ‘DianWei’],所以df2的输出是:
English Math Chinese ZhangFei 65 30 66 GuanYu 85 98 95 ZhaoYun 92 96 93 HuangZhong 88 77 90 DianWei 90 90 80
1234567 | English Math ChineseZhangFei 65 30 66GuanYu 85 98 95ZhaoYun 92 96 93HuangZhong 88 77 90DianWei 90 90 80 |
---|
在了解了Series和 DataFrame这两个数据结构后,我们就从数据处理的流程角度,来看下他们的使用方法。
Pandas允许直接从xlsx,csv等文件中导入数据,也可以输出到xlsx, csv等文件,非常方便。
import pandas as pd from pandas import Series, DataFrame score = DataFrame(pd.read_excel('data.xlsx')) score.to_excel('data1.xlsx') print score
123456 | import pandas as pdfrom pandas import Series, DataFramescore = DataFrame(pd.read_excel('data.xlsx'))score.to_excel('data1.xlsx')print score |
---|
需要说明的是,在运行的过程可能会存在缺少xlrd和openpyxl包的情况,到时候如果缺少了,可以在命令行模式下使用“pip install”命令来进行安装。
数据清洗是数据准备过程中必不可少的环节,Pandas也为我们提供了数据清洗的工具,在后面数据清洗的章节中会给你做详细的介绍,这里简单介绍下Pandas在数据清洗中的使用方法。
我还是以上面这个王者荣耀的数据为例。
data = {'Chinese': [66, 95, 93, 90,80],'English': [65, 85, 92, 88, 90],'Math': [30, 98, 96, 77, 90]} df2 = DataFrame(data, index=['ZhangFei', 'GuanYu', 'ZhaoYun', 'HuangZhong', 'DianWei'], columns=['English', 'Math', 'Chinese'])
123 | data = {'Chinese': [66, 95, 93, 90,80],'English': [65, 85, 92, 88, 90],'Math': [30, 98, 96, 77, 90]}df2 = DataFrame(data, index=['ZhangFei', 'GuanYu', 'ZhaoYun', 'HuangZhong', 'DianWei'], columns=['English', 'Math', 'Chinese']) |
---|
在数据清洗过程中,一般都会遇到以下这几种情况,下面我来简单介绍一下。
1. 删除 DataFrame 中的不必要的列或行
Pandas提供了一个便捷的方法 drop() 函数来删除我们不想要的列或行。比如我们想把“语文”这列删掉。
df2 = df2.drop(columns=['Chinese'])
12 | df2 = df2.drop(columns=['Chinese']) |
---|
想把“张飞”这行删掉。
df2 = df2.drop(index=['ZhangFei'])
12 | df2 = df2.drop(index=['ZhangFei']) |
---|
2. 重命名列名columns,让列表名更容易识别
如果你想对DataFrame中的columns进行重命名,可以直接使用rename(columns=new_names, inplace=True) 函数,比如我把列名Chinese改成YuWen,English改成YingYu。
df2.rename(columns={'Chinese': 'YuWen', 'English': 'Yingyu'}, inplace = True)
12 | df2.rename(columns={'Chinese': 'YuWen', 'English': 'Yingyu'}, inplace = True) |
---|
3. 去重复的值
数据采集可能存在重复的行,这时只要使用drop_duplicates()就会自动把重复的行去掉。
df = df.drop_duplicates() #去除重复行
12 | df = df.drop_duplicates() #去除重复行 |
---|
4. 格式问题
更改数据格式
这是个比较常用的操作,因为很多时候数据格式不规范,我们可以使用astype函数来规范数据格式,比如我们把Chinese字段的值改成str类型,或者int64可以这么写:
df2['Chinese'].astype('str') df2['Chinese'].astype(np.int64)
123 | df2['Chinese'].astype('str') df2['Chinese'].astype(np.int64) |
---|
数据间的空格
有时候我们先把格式转成了str类型,是为了方便对数据进行操作,这时想要删除数据间的空格,我们就可以使用strip函数:
#删除左右两边空格 df2['Chinese']=df2['Chinese'].map(str.strip) #删除左边空格 df2['Chinese']=df2['Chinese'].map(str.lstrip) #删除右边空格 df2['Chinese']=df2['Chinese'].map(str.rstrip)
1234567 | #删除左右两边空格df2['Chinese']=df2['Chinese'].map(str.strip)#删除左边空格df2['Chinese']=df2['Chinese'].map(str.lstrip)#删除右边空格df2['Chinese']=df2['Chinese'].map(str.rstrip) |
---|
如果数据里有某个特殊的符号,我们想要删除怎么办?同样可以使用strip函数,比如Chinese字段里有美元符号,我们想把这个删掉,可以这么写:
df2['Chinese']=df2['Chinese'].str.strip('$')
12 | df2['Chinese']=df2['Chinese'].str.strip('$') |
---|
大小写转换
大小写是个比较常见的操作,比如人名、城市名等的统一都可能用到大小写的转换,在Python里直接使用upper(), lower(), title()函数,方法如下:
#全部大写 df2.columns = df2.columns.str.upper() #全部小写 df2.columns = df2.columns.str.lower() #首字母大写 df2.columns = df2.columns.str.title()
1234567 | #全部大写df2.columns = df2.columns.str.upper()#全部小写df2.columns = df2.columns.str.lower()#首字母大写df2.columns = df2.columns.str.title() |
---|
查找空值
数据量大的情况下,有些字段存在空值NaN的可能,这时就需要使用Pandas中的isnull函数进行查找。比如,我们输入一个数据表如下:
如果我们想看下哪个地方存在空值NaN,可以针对数据表df进行df.isnull(),结果如下:
如果我想知道哪列存在空值,可以使用df.isnull().any(),结果如下:
apply函数是Pandas中自由度非常高的函数,使用频率也非常高。
比如我们想对name列的数值都进行大写转化可以用:
df['name'] = df['name'].apply(str.upper)
12 | df['name'] = df['name'].apply(str.upper) |
---|
我们也可以定义个函数,在apply中进行使用。比如定义double_df函数是将原来的数值*2进行返回。然后对df1中的“语文”列的数值进行*2处理,可以写成:
def double_df(x): return 2*x df1[u'语文'] = df1[u'语文'].apply(double_df)
1234 | def double_df(x): return 2*xdf1[u'语文'] = df1[u'语文'].apply(double_df) |
---|
我们也可以定义更复杂的函数,比如对于DataFrame,我们新增两列,其中’new1’列是“语文”和“英语”成绩之和的m倍,'new2’列是“语文”和“英语”成绩之和的n倍,我们可以这样写:
def plus(df,n,m): df['new1'] = (df[u'语文']+df[u'英语']) * m df['new2'] = (df[u'语文']+df[u'英语']) * n return df df1 = df1.apply(plus,axis=1,args=(2,3,))
123456 | def plus(df,n,m): df['new1'] = (df[u'语文']+df[u'英语']) * m df['new2'] = (df[u'语文']+df[u'英语']) * n return dfdf1 = df1.apply(plus,axis=1,args=(2,3,)) |
---|
其中axis=1代表按照列为轴进行操作,axis=0代表按照行为轴进行操作,args是传递的两个参数,即n=2, m=3,在plus函数中使用到了n和m,从而生成新的df。
在数据清洗后,我们就要对数据进行统计了。
Pandas和NumPy一样,都有常用的统计函数,如果遇到空值NaN,会自动排除。
常用的统计函数包括:
表格中有一个describe()函数,统计函数千千万,describe()函数最简便。它是个统计大礼包,可以快速让我们对数据有个全面的了解。下面我直接使用df1.descirbe()输出结果为:
df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)}) print df1.describe()
123 | df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)})print df1.describe() |
---|
有时候我们需要将多个渠道源的多个数据表进行合并,一个DataFrame相当于一个数据库的数据表,那么多个DataFrame数据表的合并就相当于多个数据库的表合并。
比如我要创建两个DataFrame:
df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)}) df2 = DataFrame({'name':['ZhangFei', 'GuanYu', 'A', 'B', 'C'], 'data2':range(5)})
123 | df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)})df2 = DataFrame({'name':['ZhangFei', 'GuanYu', 'A', 'B', 'C'], 'data2':range(5)}) |
---|
两个DataFrame数据表的合并使用的是merge()函数,有下面5种形式:
1. 基于指定列进行连接
比如我们可以基于name这列进行连接。
df3 = pd.merge(df1, df2, on='name')
12 | df3 = pd.merge(df1, df2, on='name') |
---|
2. inner内连接
inner内链接是merge合并的默认情况,inner内连接其实也就是键的交集,在这里df1, df2相同的键是name,所以是基于name字段做的连接:
df3 = pd.merge(df1, df2, how='inner')
12 | df3 = pd.merge(df1, df2, how='inner') |
---|
3. left左连接
左连接是以第一个DataFrame为主进行的连接,第二个DataFrame作为补充。
df3 = pd.merge(df1, df2, how='left')
12 | df3 = pd.merge(df1, df2, how='left') |
---|
4. right右连接
右连接是以第二个DataFrame为主进行的连接,第一个DataFrame作为补充。
df3 = pd.merge(df1, df2, how='right')
12 | df3 = pd.merge(df1, df2, how='right') |
---|
5. outer外连接
外连接相当于求两个DataFrame的并集。
df3 = pd.merge(df1, df2, how='outer')
12 | df3 = pd.merge(df1, df2, how='outer') |
---|
Pandas的DataFrame数据类型可以让我们像处理数据表一样进行操作,比如数据表的增删改查,都可以用Pandas工具来完成。不过也会有很多人记不住这些Pandas的命令,相比之下还是用SQL语句更熟练,用SQL对数据表进行操作是最方便的,它的语句描述形式更接近我们的自然语言。
事实上,在Python里可以直接使用SQL语句来操作Pandas。
这里给你介绍个工具:pandasql。
pandasql 中的主要函数是 sqldf,它接收两个参数:一个SQL 查询语句,还有一组环境变量globals()或locals()。这样我们就可以在Python里,直接用SQL语句中对DataFrame进行操作,举个例子:
import pandas as pd from pandas import DataFrame from pandasql import sqldf, load_meat, load_births df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)}) pysqldf = lambda sql: sqldf(sql, globals()) sql = "select * from df1 where name ='ZhangFei'" print pysqldf(sql)
12345678 | import pandas as pdfrom pandas import DataFramefrom pandasql import sqldf, load_meat, load_birthsdf1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)})pysqldf = lambda sql: sqldf(sql, globals())sql = "select * from df1 where name ='ZhangFei'"print pysqldf(sql) |
---|
运行结果:
data1 name 0 0 ZhangFei
123 | data1 name0 0 ZhangFei |
---|
上面这个例子中,我们是对“name='ZhangFei”“的行进行了输出。当然你会看到我们用到了lambda,lambda在python中算是使用频率很高的,那lambda是用来做什么的呢?它实际上是用来定义一个匿名函数的,具体的使用形式为:
lambda argument_list: expression
12 | lambda argument_list: expression |
---|
这里argument_list是参数列表,expression是关于参数的表达式,会根据expression表达式计算结果进行输出返回。
在上面的代码中,我们定义了:
pysqldf = lambda sql: sqldf(sql, globals())
12 | pysqldf = lambda sql: sqldf(sql, globals()) |
---|
在这个例子里,输入的参数是sql,返回的结果是sqldf对sql的运行结果,当然sqldf中也输入了globals全局参数,因为在sql中有对全局参数df1的使用。
和NumPy一样,Pandas有两个非常重要的数据结构:Series和DataFrame。使用Pandas可以直接从csv或xlsx等文件中导入数据,以及最终输出到excel表中。
我重点介绍了数据清洗中的操作,当然Pandas中同样提供了多种数据统计的函数。
最后我们介绍了如何将数据表进行合并,以及在Pandas中使用SQL对数据表更方便地进行操作。
Pandas包与NumPy工具库配合使用可以发挥巨大的威力,正是有了Pandas工具,Python做数据挖掘才具有优势。