Pandas简介
Pandas是基于Numpy的一个开源库,它被广泛用于快速分析数据,以及数据清洗和准备等工作
Pandas中有两类非常重要的数据结构,就是序列Series和数据框DataFrame
Series类似于Numpy中一维数组,可以使用一维数组的可用函数和方法,而且可以通过索引标签的方式获取数据,具有索引的自动对齐功能
DataFrame类似于Numpy中的二维数组,同样可以使用Numpy数组的函数和方法,还具有一些其他灵活的使用
相关操作
创建
DataFrame创建
通过二维数组创建
通过字典方式创建
通过数据框创建
import numpy as np
import pandas as pd
# 第一种,通过二维数组创建DataFrame
arr1 = np.arange(12).reshape(3,4)
df1 = pd.DataFrame(arr1)
# 第二种 通过字典的方式创建DataFrame
dict1 = {"a":[1,2,3,4],"b":[5,6,7,8],"c":[9,10,11,12],"d":[12,14,15,16]}
df2 = pd.DataFrame(dict1)
# 嵌套字典
dict2 = {"one":{"a":1,"b":2,"c":3,"d":4,"e":5},
"two":{"a":6,"b":7,"c":8,"d":9,"e":10},
"three":{"a":11,"b":12,"c":13,"d":14,"e":15}}
df3 = pd.DataFrame(dict2)
print(df3)
# 第三种 通过数据框创建数据框
df4 = df3[['one','three']]
print(df4)
Series创建
通过一维数组创建序列
通过字典的方式创建序列
通过DataFrame中的某一行或者某一列创建序列
import numpy as np
import pandas as pd
# 通过一维数组创建Series
arr1 = np.arange(10)
s1 = pd.Series(arr1)
# 通过字典的方式创建Series
dict1 = {"a":1,"b":2,"c":3,"d":4,"e":5}
s2 = pd.Series(dict1)
# 通过DataFrame中的某一行或者某一列创建Series
dict2 = {"one":{"a":1,"b":2,"c":3,"d":4,"e":5},
"two":{"a":6,"b":7,"c":8,"d":9,"e":10},
"three":{"a":11,"b":12,"c":13,"d":14,"e":15}}
df1 = pd.DataFrame(dict2)
# 第一列
s3 = df1['one']
# 第一行
s4 = df1.iloc[0]
print(s4)
数据索引index
查询数据,需要使用索引有针对的选取原数据中的子集,指定行、指定列等
无论是Series还是DataFrame,最左侧始终有一个非原始数据对象,这个就是数据索引
通过索引获取目标数据,对数据进行一系列的操作
- 通过index属性获取序列的索引值
- 更改index
- 通过索引获取数据
- 自动化对齐
import numpy as np
import pandas as pd
s = pd.Series(np.array([1,2,3,4,5,6,7,8]))
# 如果不给索引一个指定索引值,序列会自动生成一个从0开始的自增索引
# 通过index属性获取序列索引值
print(s.index)
# 为index重新赋值
s.index=['a','b','c','d','e','f','g','h']
print(s.index)
# 序列有了索引,就可以通过索引获取数据
print(s[3])
print(s['d'])
print(s[[1,3,5]])
print(s[['b','d','f']])
print(s[4:])
print(s['e':])
print(s[0:3])
# 通过索引标签获取数据,末端标签数据也是有返回的
print(s['a':'d'])
# 自动化对齐
s6=pd.Series(np.array([10,15,20,30,55,80]),index=['a','b','c','d','e','f'])
print("序列6:",s6)
s7=pd.Series(np.array([12,11,13,15,14,16]),index=['a','c','g','b','d','f'])
print("序列7:",s7)
#s6中不存在g索引,s7中不存在e索引,所以数据运算会产生两个缺失值NaN。
print(s6+s7)
#可以注意到这里的算术运算自动实现了两个序列的自动对齐
#对于数据框的对齐,不仅是行索引的自动对齐,同时也会对列索引进行自动对齐,数据框相当于二维数组的推广
print(s6/s7)
查询数据
test_data = pd.read_csv("test_set.csv")
test_data.head()
# factorize函数可以将Series中的标称型数据映射称为一组数字,相同的标称型映射为相同的数字。
# factorize函数的返回值是一个tuple(元组),元组中包含两个元素。第一个元素是一个array,其中的元素是标称型元素映射为的数字;
# 第二个元素是Index类型,其中的元素是所有标称型元素,没有重复。
test_data['job'],jnum = pd.factorize(test_data['job'])
test_data['job'] = test_data['job'] + 1
test_data['marital'],jnum=pd.factorize(test_data['marital'])
test_data['marital']=test_data['marital']+1
test_data['education'],jnum=pd.factorize(test_data['education'])
test_data['education']=test_data['education']+1
test_data['default'],jnum=pd.factorize(test_data['default'])
test_data['default']=test_data['default']+1
test_data['housing'],jnum=pd.factorize(test_data['housing'])
test_data['housing']=test_data['housing']+1
test_data['loan'],jnum=pd.factorize(test_data['loan'])
test_data['loan']=test_data['loan']+1
test_data['contact'],jnum=pd.factorize(test_data['contact'])
test_data['contact']=test_data['contact']+1
test_data['month'],jnum=pd.factorize(test_data['month'])
test_data['month']=test_data['month']+1
test_data['poutcome'],jnum=pd.factorize(test_data['poutcome'])
test_data['poutcome']=test_data['poutcome']+1
# 查询数据的前5行
test_data.head()
# 查询数据的后5行
test_data.tail()
# 查询指定的行
test_data.iloc[[0,2,3,4,5,6]]
# 查询指定的列
test_data[['ID','age','job','education']].tail()
# 查询指定的行和列
test_data.loc[[0,2,3,4,5,6],['ID','age','job','education']]
# 以下通过布尔索引实现数据的自己查询
# 查询年龄为51的信息
test_data[test_data['age']==51].head()
# 查询工作为5年以上的年龄在51以上的信息,多个条件的查询,需要在&或者|的两端的条件括起来
test_data[(test_data['job'] > 5) & (test_data['age'] > 51)].head()
# 查询工作为5以上,年龄在51的人员的housing,loan,contact和poutcome
test_data[(test_data['job'] > 5) & (test_data['age'] > 51)][['housing','loan','contact','poutcome']].head()
对DataFrames进行统计分析
对于Series,有
- 总和
- 均值
- 最大最小值
- 中位数
- 众数
- …
对于DataFrame - df.shape:查看维度
- df.info:数据表的基本信息(维度、列名称、数据格式、所占空间等)
- df.dtypes:每一列数据的格式
- df.columns:查看列名称
- …
a = np.random.normal(size=10)
s1 = pd.Series(2 * a + 3)
s2 = np.random.f(2,4,size=10)
s3 = np.random.randint(1,100,size=10)
# 非空元素的计算
s1.count()
# 最小值
s1.min()
# 最大值
s1.max()
# 最小值位置
s1.idxmin()
# 最大值位置
s1.idxmax()
# 求和
s1.sum()
# 平均数
s1.mean()
# 中位数
s1.median()
# 众数
s1.mode()
# 10%分位数 TODO这个没明白怎么算
s1.quantile(0.2)
# 方差
s1.var()
# 标准差
s1.std()
# 平均绝对偏差
s1.mad()
# 偏度
s1.skew()
# 峰值
s1.kurt()
# 一次性输出多个描述性统计指标
s1.describe()
#自定义一个函数,将这些统计描述指标全部汇总到一起
def stats(x):
return pd.Series([x.count(),x.min(),x.idxmin(),x.quantile(.25),x.median(),
x.quantile(.75),x.mean(),x.max(),x.idxmax(),x.mad(),x.var(),x.std(),x.skew(),x.kurt()],
index=['Count','Min','Which_Min','Q1','Median','Q3','Mean','Max','Which_Max','Mad','Var','Std','Skew',
'Kurt'])
stats(s1)
#当实际工作中我们需要处理的是一系列的数值型数据框,可以使用apply函数将这个stats函数应用到数据框中的每一列
df=pd.DataFrame(np.array([s1,s2,s3]).T,columns=['x1','x2','x3']) #将之前创建的s1,s2,s3数据构建数据框
df.apply(stats)
# 以上很简单的创建了数值型数据的统计性描述,但对于离散型数据就不能使用该方法了。
# 我们在统计离散变量的观测数、唯一值个数、众数水平及个数,只需要使用describe方法就可以实现这样的统计了。
train_data=pd.read_csv('train_set.csv')
# test_data.drop(['ID'],inplace=True,axis=1)
train_data.head()
#离散型数据的描述
train_data['job'].describe()
#数值型数据的描述
test_data['job'].describe()
# 除了以上简单的描述性统计之外,还提供了连续变量的相关系数(corr)和协方差(cov)的求解
#相关系数的计算方法可以调用pearson方法、kendall方法、或者spearman方法,默认使用的是pearson方法
df.corr()
df.corr('spearman')
df.corr('pearson')
df.corr('kendall')
#如果只关注某一个变量与其余变量的相关系数的话,可以使用corrwith,如下方只关注x1与其余变量的相关系数
df.corrwith(df['x1'])
#数值型变量间的协方差矩阵
df.cov()
pandas实现SQL操作
增
- 通过concat函数实现增加行
- 通过columns增加列
删 - del:删除整合数据框
- drop:删除指定行、列
改 - 结合索引和赋值的方式
查 - groupby():聚合分组
- sort_values():排序
- merge():多表链接
# pandas实现对数据的增删改查
# 增:添加新行或增加新列
dict={'Name':['LiuShunxiang','Zhangshan'],
'Sex':['M','F'],
'Age':[27,23],
'Height':[165.7,167.2],
'weight':[61,63]}
student1=pd.DataFrame(dict)
dict={'Name':['Liu','Zhang'],
'Sex':['M','F'],
'Age':[27,23],
'Height':[165.7,167.2],
'weight':[61,63]}
student2=pd.DataFrame(dict)
#将student2中的数据新增到student1中,可以通过concat函数实现
student3=pd.concat([student1,student2],ignore_index='Ture') #concat函数对index无视
student3
#添加新列---增加的新列没有赋值,就会出现NAN的形式
pd.DataFrame(student2,columns=['Age','Heught','Name','Sex','weight','Score'])
# 删:删除表、观测行或变量列
#删除整个数据框
del student2
# student2 出现name 'student2' is not defined
#删除指定行
student3.drop([0])
#删除25岁以下的学生
student3[student3['Age']<25]
#删除指定的列
student3.drop(['Height','weight'],axis=1)
# 不论删除行还是列,都可以通过drop方法实现,只需要设定好删除的轴即可,
# 即调整drop方法中的axis参数。默认参数为0,即删除行观测数据,如果需要删除列变量,则需要设置为1.
# 改:修改原始记录的值
#如果发现表中的数据错了,如何更改原来得值呢?尝试结合布尔索引和赋值的方法
student3
#假设需要修改liu学生的身高为173
student3.loc[student3['Name']=='Liu','Height']=173
student3
# 查:类似上边的数据查询部分
# 聚合:groupby()
student3.groupby('Sex').mean()
#多个分组变量,例如根据年龄和性别分组,计算身高和体重的平均值
student3.groupby(['Sex','Age']).mean()
#对每个分组计算多个统计量
student3.drop('Age',axis=1).groupby('Sex').agg([np.mean,np.median])
#排序:sort_values
series=pd.Series(np.array(np.random.randint(1,20,10)))
series
series.sort_values() #默认按值升序排列
series.sort_values(ascending=False) #按降序排列
#数据框中按值排列
student3.sort_values(by=['Sex','Age'])
#多表链接-merge
dict2={'Name':['Alfred','Alice','Barbara','Carol','Henry','Jeffrey','Judy','Philip','Robert','william'],
'Score':[88,76,89,67,79,90,92,86,73,77]}
score=pd.DataFrame(dict2)
student3['Name']=['Alfred','Alice','Barbara','Carol']
#把学生表和成绩表做一个关联
stu_score1=pd.merge(student3,score,on='Name') #默认情况下实现的是两个表之间的内连接,即返回两张表中共同部分的数据
# 使用how参数设置连接的方式,left为左连接,right为右连接,outer为外连接
#保留student3表中的所有信息,同时将score表的信息与之配对,能配多少配多少,对于没有配上的Name,将会显示成绩为Nan
stu_score2=pd.merge(student3,score,on='Name',how='left')
#保留score表中的所有信息,同时将student3表的信息与之配对,能配多少配多少,对于没有配上的score,将会显示Nan
stu_score3=pd.merge(student3,score,on='Name',how='right')
stu_score4=pd.merge(student3,score,on='Name',how='outer')
对缺失值的处理
现实中的数据存在很多噪音的同时,缺失值也非常的常见。缺失值的存在会影响后期的数据分析或挖掘工作,那么缺失值的处理有哪些方法呢?
删除法
当数据中某个变量大部分值都会缺失值时,可以考虑删除该变量;
当缺失值时随机分布的,且缺失的数量并不是很多时,可以删除这些缺失的观测;
train_data.head()
offline_data=pd.read_csv('ccf_offline_stage1_train.csv')
offline_data.head()
s=offline_data['Coupon_id']
s.size
sum(pd.isnull(s)) #查看包含多少个缺失值
#直接删除缺失值 默认情况下,dropna会删除任何含有缺失值的行
s.dropna()
#构造数据框试试
df=pd.DataFrame([[1,1,2],[3,5,np.nan],[13,21,34],[55,np.nan,10],
[np.nan,np.nan,np.nan],[np.nan,1,2]],columns=['x1','x2','x3'])
df.dropna()
df=pd.DataFrame([[1,1,2],[3,5,np.nan],[13,21,34],[55,np.nan,10],
[np.nan,np.nan,np.nan],[np.nan,1,2]],columns=['x1','x2','x3'])
df.dropna(how='all') #只删除所有行为缺失值的观测
df=pd.DataFrame([[1,1,2],[3,5,np.nan],[13,21,34],[55,np.nan,10],
[np.nan,np.nan,np.nan],[np.nan,1,2]],columns=['x1','x2','x3'])
df.dropna(how='any') #删除有行为缺失值的观测,
df=pd.DataFrame([[1,1,2,np.nan],[3,5,np.nan,np.nan],[13,21,34,np.nan],[55,np.nan,10,np.nan],
[np.nan,np.nan,np.nan,np.nan],[np.nan,1,2,np.nan]],columns=['x1','x2','x3','x4'])
print(df)
df.dropna(how='all',axis=1) #删除全为nan的那些列
#利用thresh,保留一些为nan的值
df=pd.DataFrame([[1,1,2,np.nan],[3,5,np.nan,np.nan],[13,21,34,np.nan],[55,np.nan,10,np.nan],
[np.nan,np.nan,np.nan,np.nan],[np.nan,1,2,np.nan]],columns=['x1','x2','x3','x4'])
df.dropna(thresh=3) #在行方向上至少有3个非NAN的项保留
df=pd.DataFrame([[1,1,2,np.nan],[3,5,np.nan,np.nan],[13,21,34,np.nan],[55,np.nan,10,np.nan],
[np.nan,np.nan,np.nan,np.nan],[np.nan,1,2,np.nan]],columns=['x1','x2','x3','x4'])
df.dropna(thresh=1)
df=pd.DataFrame([[1,1,2,np.nan],[3,5,np.nan,np.nan],[13,21,34,np.nan],[55,np.nan,10,np.nan],
[np.nan,np.nan,np.nan,np.nan],[np.nan,1,2,np.nan]],columns=['x1','x2','x3','x4'])
df.dropna(thresh=3,axis=1) #在列方向上至少保留有3个非NAN的项保留
替补法
对于连续变量,如果变量的分布近似或就是正态分布的话,可以用均值替代那些缺失值;
如果变量是有偏的,可以使用中位数来代替那些缺失值;
对于离散型变量,一般使用众数去替换那些存在缺失的预测;
fillna函数的参数:
- value:用于填充缺失值的标量值或者字典对象
- method:插值方式,如果函数调用时,未指定其他参数的话默认值fill
- axis:待填充的轴默认值axis=0
- inplace:修改调用这对象而不产生副本
- limit:(对于前向和后项填充)可以连续填充的最大数量
df=pd.DataFrame([[1,1,2],[3,5,np.nan],[13,21,34],[55,np.nan,10],
[np.nan,np.nan,np.nan],[np.nan,1,2]],columns=['x1','x2','x3'])
df
#使用一个常量来填补缺失值,可以使用fillna函数实现简单的填补工作
#1用0填补所有缺失值
df.fillna(0)
#2采用前项填充或后项填充
df.fillna(method='ffill') #用一个观测值填充
df.fillna(method='bfill') #用后一个观测值填充--这样会导致最后边的无法填充Nan
#3使用常量填充不同的列
df.fillna({'x1':1,'x2':2,'x3':3})
#4使用均值或中位数填充各自的列
x1_median=df['x1'].median()
x2_mean=df['x2'].mean()
x3_mean=df['x3'].mean()
print(x1_median,x2_mean,x3_mean)
df.fillna({'x1':x1_median,'x2':x2_mean,'x3':x3_mean})
使用填充法时,相对于常数填充或者前项、后项填充,使用各列众数,均值或中位数填充要更加合理些,这也是工作中常用的一个快捷手段。
实现excel的数据透视表功能
pivot_table(data,values=None,index=None,columns=None,aggfunc=‘mean’, fill_value=None,margins=False,dropna=True,margins_name=‘All’)
- data:需要进行数据透视表操作的数据框
- values:指定需要聚合的字段
- index:指定某些原始变量作为行索引
- columns:指定哪些离散的分组变量
- aggfunc:指定相应的聚合函数
- fill_values:使用一个常数替代缺失值,默认不替换
- margins:是否进行行或列的汇总,默认不汇总
- dropna:默认所有观测为缺失的列
- margins_name:默认行汇总或列汇总的名称为‘ALL’
import numpy as np
import pandas as pd
test_data = pd.read_csv("test_set.csv")
test_data.head()
#marital作为分组变量,balance作为数值变量做统计汇总
pd.pivot_table(test_data,values=['balance'],columns=['marital'])
#marital作为1个分组变量,balance,housing作为两个数值变量做统计汇总
pd.pivot_table(test_data,values=['balance','housing'],columns=['marital'])
#marital,job作为2个分组变量,balance作为1个数值变量做统计汇总
pd.pivot_table(test_data,values=['balance'],columns=['marital','job'])
#marital,job作为2个分组变量,balance,housing作为两个数值变量做统计汇总
pd.pivot_table(test_data,values=['balance','housing'],columns=['marital','job'])
# 很显然,这样的结果并不想Excel中预期的那样,该如何变成列联表的形式呢?很简单,只需将结果进行非堆叠操作即可。这样的结果看起来更舒服一些
pd.pivot_table(test_data,values=['balance','housing'],columns=['marital','job']).unstack()
#使用多个聚合函数
pd.pivot_table(test_data,values=['balance','housing'],columns=['marital'],
aggfunc=[np.mean,np.median,np.std])
多层索引的使用
序列的多层索引类似于Excel中如下形式。
数据框的多层次索引,多层索引的形式类似excel中的如下形式。
import numpy as np
import pandas as pd
#Series的多层索引
s=pd.Series([1,2,3,4],index=[['小张','小张','老王','老王'],
['期中','期末','期中','期末']])
s
s[['小张']] #取回最外层索引为‘小张’的所有数据
s[:,'期中'] #取回最内层所有为‘期中’的数据
#将多层次索引的序列转换为数据框的形式
s.unstack()
#构造一个类似的高维数据框
df=pd.DataFrame(np.random.randint(10,50,20).reshape(5,4),
index=[['A','A','A','B','B'],[1,2,3,1,2]],
columns=[['x','x','x','y'],['x1','x2','x3','y']])
df
#通过外层索引取出大块数据
df['x']
df.loc[['A'],:]
#在数据框中使用多层索引,可以将整个数据集控制在二维表结构中,这对于数据重塑和基于分组的操作(如数据透视表的生成)比较有帮助。
#以test_data二维数据框为例,构造一个多层索引数据集
pd.pivot_table(test_data,index=['marital','loan'])