Python|python中的pandas库

pandas的数据结构和基本功能 Series对象 利用pd.Series函数生成series对象

#series对象相当于一维数组 import pandas as pd a=pd.Series([1,2,3]) #dtype为int64 a=pd.Series(["1","2","3"]) #dtype为object

series对象的切片
a=pd.Series(np.arange(10)) a[0::3] #前两个参数是范围,左包含右不包含,第三个参数是步长x1=pd.Series(np.arange(4),index=list("abcd")) x1["a":"c"] #当参数不是数字时,左右都包含

布尔索引
a=pd.Series(np.random.uniform(-1,1,10)) #从(-1,1)的均匀分布中随机抽取10个数 a[a>0.3]#返回布尔值为True对应的value

astype方法,series类型转换
series1=pd.Series(np.arange(10)) series1.astype(str) #将整数变成字符串c=pd.Series(['1','2','a']) c.astype(np.float,errors='ignore') #参数errors有两个可能取值,一个是"raise",一个是"ignore"。 #raise 如果在转化过程中出现错误, 则抛出一个错误提示,并停止程序执行。 #"ignore" 如果在转化过程中出现错误,则忽略这个错误,如果出现转化错误,则series的类型为object

series类型转换–pd.to_numeric方法
有时候会涉及到将 object 类型转为其他类型,常见的有转为数字、日期、时间差,Pandas 中分别对应 to_numeric、to_datetime、to_timedelta 方法。
series1=pd.Series(["1","2","a"]) pd.to_numeric(series1,errors="coerce") #其他类型转化为数字 #errors参数有三个可能取值,分别是'ignore', 'raise', 'coerce'(强迫), 默认的取值是 'raise'.

series对象的map方法
#将字符串转化为float series2=pd.Series(["1","2","a"]) def f1(x): try: a=float(x) except: a=np.nan return a series2.map(f1) #Series对象的运算,类型必须相同 series1=pd.Series([1,2,3]) series1.map(lambda x:x+2)

DataFrame(数据框)对象 数据框对象的生成 pd.DataFrame–数据框对象的手动生成
data1=pd.DataFrame(np.arange(24).reshape(6,4),columns=["a",1,"c","e"]) data1#字典形式 data2=pd.DataFrame({"x":np.random.rand(5),"y":np.random.rand(5)}) data2

pd.read_csv----外部文件读取
#导入CSV文件,如果代码和导入的文件在一个路径下,直接写文件名,如果路径不同,导入时注意用双斜杠 pd.read_csv('working.csv',encoding='GBK') #UTF-8是国际编码,GBK是国内编码

pd.read_excel----外部文件读取
这个函数的参数非常多,一般情况下保持默认就可以
#当删除第一行大标题后,变量的名字就变成了第一行,索引值为0 a=pd.read_excel('chapter3_1.xls',sheet_name='Sheet1',nrows=10,skiprows=1,header=0) #导入某个Excel文件中第一个表的10行数据,不包含标题,跳过大标题,变量名索引值变成了0

查看数据框基本信息(info方法)
data1.info()

查看前/后几条信息(head,tail方法)
data1.head() #如果省略括号内的参数,则显示前五行 data1.tail(3) #如果省略括号内的参数,则显示后五行

查看数据框的形状——shape属性
data1.shape#返回一个元组

values、columns、index属性
data1.values #返回的是一个ndarray实例 data1.columns #返回的是一个类似的一维数组,是变量名 data1.index #返回索引值的范围

数据框对象的转置
data1.T

数据框对象的索引和切片
#切取一列或几列 data1=pd.DataFrame(np.arange(12).reshape(3,4),columns=["a",1,"c","e"] ) #如果列名是字符串则有如下两种方式把列调出来 #方法一 data1["a"] #方法二 data1.a #如果列名是数字则只能采用第一种方式进行切片 data1[["a","c"]] #切取a和c列#切取一行或者几行 data1[0:0] #切取第0行,注意不要写成data1[0],会有错误提示 data1[0:3]#切取前三行

loc方法:显式索引
data1=pd.DataFrame(np.random.rand(4,3),columns=["x1","x2","x3"],index=["a","b","c","d"]) #语法 data1.loc[索引行,索引列 ] data1.loc[:,"x1":"x3"] #索引列名为x1,x3的所有行 data1.loc[["a","b","c"],["x1","x2","x3"]] #注意方括号内第一个参数是行标签列表,切取不连续的行和列 data1.loc["a":"b","x1":"x3"] #切取连续的行和列,注意使用显式索引的时候,冒号右侧的列或行是包含的

iloc方法:隐式索引
使用 iloc 也就是 index_loc 这种方式不看你的行索引和列索引是什么名称, 只看数据是处于表中的一个什么位置.
data1=pd.DataFrame(np.random.rand(4,3),columns=["x1","x2","x3"],index=["a","b","c","d"]) #语法 data1.iloc[索引行,索引列 ] data1.iloc[2:4:1,1:3] #切片行的索引值2到4,步长为1,列的索引值1到3 #需要注意的是使用隐式索引的时候,冒号右侧的列或者行是不包含的

ix方法
ix是loc和iloc的结合,可以混用数字(隐式索引)和自定的标签(显式索引)进行索引。
data1=pd.DataFrame(np.random.rand(4,3),columns=["x1","x2","x3"],index=["a","b","c","d"]) data1.ix[2:4,"x1":"x2"]

布尔索引
data1[(data1.x1>0.5) & (data1.x2>0.5)] #注意如果有多个条件,每个条件要用括号括起来

删除一列(pop,drop方法)
data1.pop("x3") #这个方法会直接修改data1实例。如果删除的列不存在会有错误提示 data1.drop(columns=["x1"],axis=1,inplace=True) #inplace参数设定为True的意思是直接作用于data1数据框实例,否则返回新实例 #errors 参数有'ignore', 'raise'两个取值 #相比之下drop方法的应用更广泛

新增一列
#新增一列常量 data1["z1"]=10 #生成一列秩变量 data1['x2'].rank(method='first',ascending=False) #按降序对x2这一列排序 #method参数用来设置遇到相同值的时候如何计算秩,method : {'average', 'min', 'max', 'first', 'dense'} #根据一列原有数据生成一列新数据 data1["z2"]=data1["x2"]**2 #方法1 data1["z2"]=data1["x2"].map(lambda x:x**2) #方法2 #根据原有多列数据生成一列新数据 data1["z3"]=data1["x1"]+data1["x2"] data1["z4"]=data1.apply(lambda x:max(x["x1"],x["x2"]),axis=1) #因为是生成一列,所以axis=1,axis参数的默认取值是1. a=pd.DataFrame(np.random.randint(60,100,(10,3)),columns=["语文","数学","英语"]) a["总分"]=a.apply(np.sum,axis=1) #另一种方法 a[["语文","数学","英语"]].sum(1)

map,apply方法
data1=pd.DataFrame(np.random.rand(4,3)) #数据框的apply,map方法是将函数应用于数据框的每一个单元格。 data1.apply(lambda x:x+1)

数据框修改列名
data1=pd.DataFrame(np.random.rand(4,3),columns=["x1","x2","x3"]) data1.rename(columns={"x1":"z1","x2":"z2"}) #如果是修改索引值,也可以采用rename方法,设定index参数即可。也是一个字典对象 #这个方法里面有inplace参数

DataFrame对象的导出
data1.to_csv("temp1.csv",index=False) #不想输出索引列,可以将index参数设定为False,默认是True #需要注意的是,如果数据框中的某个单元格是缺失值,输出到csv文件之后,它还是缺失值,并且是空白的

缺失值处理 缺失值的产生 通过读取数据产生
data1=pd.read_excel("test.xlsx") pd.isna(np.nan)#pd.isna会对下列几个判断是否是缺失值

定义异常值为缺失值
通过map方法定义异常值为缺失值
#通过下面的命令执行,在数据框中性别的缺失值显示为NaN def f1(x): if x in {"男","女"}: return x else: return np.nan data1.性别=data1.性别.map(f1) data1.isnull()#判断是否含有缺失值 data1.isna() #pd.isna对于各种缺失情况的判断更加准确稳定

通过loc定义缺失值
data1.loc[3,"性别"]=np.nan

处理缺失值 缺失和非缺失的判断
data1.isnull() data1.notnull() #求各个变量的缺失值比例 data1.isnull().mean() (data1.isnull().sum())/(data1.shape[0])

布尔索引
data1[data1.身高.isnull()] data1[(data1.身高.isnull()) | (data1.性别.isnull())]

丢弃缺失值:dropna方法
data1.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False) #axis 参数用于控制行或列,跟其他不一样的是,axis=0 (默认)表示操作行,axis=1 表示操作列 #how 参数可选的值为 any(默认) 或者 all。any 表示一行/列有任意元素为空时即丢弃,all 一行/列所有值都为空时 才丢弃 #subset 参数表示删除时只考虑的索引或列名 #thresh参数的类型为整数,它的作用是,比如 thresh=3,会在一行/列中至少有 3 个非空值时将其保留# 一行数据中只要姓名或身高存在空值即删除 data1.dropna(axis=0, how="any", subset=["姓名", "身高"])

对含有缺失值的列转换类型 用astype将列转化为str
#身高这一列含有缺失值 data1["身高1"]=data1["身高"].astype(str) #用astype将一列变量转化为str,原来的缺失值或者变成了字符串"nan"或者"None",用isnull对转化之后的列进行判断,就会判断成非缺失值

用astype将列转化为?oat
data1["身高"].astype(str).astype(float) #当列里有非数值字符串时,运行会出错 #字符串是"nan",用astype,转化为?oat,会变成缺失值NaN

用pd.to_numeric将列强制转化为数值
pd.to_numeric(data1["性别"],errors="coerce") '''errors参数设定为coerce的意思是如果不是数值格式的字符串则会转化为缺失值。默认值为raise, 转化出现错误时就会有错误提示'''

map方法为更加通用和保险的方式
def f1(x): try: a=float(x) except: a=np.nan return a data1["性别"].map(f1)

填充缺失值 固定值填充
填充缺失值时,常见的一种方式是使用一个标量来填充。如果你要填充的列是一个数值列,则可以填充缺失值为一个固定的数值。如果你要填充的列是一个object(通常为字符串)列,则可以用""填充缺失值,这样进行字符串运算的时候就不容易出错了
data1.身高.fillna(180) #如果inplace参数为True则直接作用于原实例 data1.fillna(value=https://www.it610.com/article/{"性别":"","身高":180})

上下文填充
#设置参数 method='pad' 或 method='ffill' 可以使用前一个有效值来填充 data1.性别.fillna(method="ffill") #设置参数 method='bfill' 或 method='backfill' 可以使用后一个有效值来填充 data1.性别.fillna(method="backfill")

其他列填充
data1.身高.fillna(data1.体重)

线性插补
data1["身高1"]=data1.身高.interpolate() #出现新的一列,缺失值用众数填补

数据框的合并、排序、描述统计、分箱 表合并 表的纵向合并相对来说比较容易,而且还不易出错。表的横向合并比较麻烦和容易出错
表的纵向合并:append方法
data1=pd.DataFrame(np.random.rand(3,4),columns=["x1","x2","x3","x4"]) data2=pd.DataFrame(np.random.rand(3,4),columns=["x2","x3","x4","x5"]) data1.append(data2) '''ignore_index参数设定为True,则意味着重新对合并后的数据进行索引,为了保证index索引无重复,进行纵向合并的时候好加上这个参数。''' data1.append(data2,ignore_index=True)

表的纵向合并pd.concat
concat函数既可以进行纵向合并,又可以进行横向合并
#axis参数的取值为0的时候,表示进行纵向合并 #ignore_index参数的意思和前面append方法的ignore_index参数意思一样 pd.concat([data1,data2],axis=0,ignore_index=True)

表的横向合并pd.concat
#axis参数为1的时候表示进行横向合并 data1=pd.DataFrame(np.random.rand(3,2),columns=["x1","x2"]) data2=pd.DataFrame(np.random.rand(4,2),columns=["x2","x3"]) pd.concat([data1,data2],axis=1) #加上join参数的设定,如果为’inner’得到的是两表的交集,如果是outer,得到的是两表的并集 pd.concat([data1,data2],join="inner",axis=1)

总体来说,pd.concat不太适合我们以往的数据合并习惯,因此不建议用这个方法进行横向合并。对于横向合并建议 用下面学的merge方法
表的横向合并:pd.merge方法
参数how表示连接方式,有四个可能取值’left’, ‘right’, ‘outer’, ‘inner’, 默认的取值是 ‘inner’。 left_on是设定左表的连接变量,right_on是设定右表的连接变量。 su?xes是设定重复列的变量名后缀,以便知道重复列来自哪张表
data1=pd.merge(test1,test2,left_on="pid",right_on="pid",how="outer",suffixes=("_1","_2"))

数据框排序 sort_values方法
data1=pd.DataFrame(np.random.rand(4,3),columns=["x1","x2","x3"],index=np.arange(4)[::-1]) #参数ascending=True是升序,ascending=False是降序 #inplace 参数的默认取值是False,如果设定为True,则会直接作用于原数据框实例 data1.sort_values(by="x1",ascending=True) data1.sort_values(by=["x1","x2"],ascending=[True,False])

sort_index方法
data1.sort_index(ascending=True) #sort_index(axis=0, level=None, ascending=True,inplace=False,by=None)

变量的描述性统计 数值变量的描述统计
对非数值类型的变量进行描述统计时给出了如下几个指标:观测值总数,去重后的个数、常见的 值(众数)、常见的值的频数
#如果括号内不设定任何参数,则会对所有数值类型的变量进行描述统计 #通过include参数可以选择对哪些类型的变量进行描述统计 #通过exclude参数可以选择不对哪些类型的变量进行描述统计 #percentiles参数可以设定报告哪些分位数,默认是[.25, .5, .75],中位数是默认有的 data1.describe(exclude=["object"],percentiles=[0.1,0.2])

变量有哪些唯一值
data1["性别"].unique() #返回了一个数组

变量的值计数统计
data1['性别'].value_counts()#默认会进行频数降序排列

数据框或者序列的分组
data1.groupby(data1["性别"]) #我们把返回的实例叫做分组(GroupBy)实例,可以多个分组

变量的分组汇总
data1["年龄"].groupby(data1["性别"]).max() data1.groupby(["性别"]).max() #除了max还有min,mean,median,sum,quantile,var,std,skew等

变量的分组描述
data1["年龄"].groupby(data1["性别"]).describe()

分组对象的聚合方法
data1[["年龄","受教育程度"]].groupby(data1.性别).agg(['max','min','median']) data1["年龄"].groupby(data1.性别).agg(['max','min','median'])

分组对象的transform方法 和agg方法的区别在于transform方法返回的对象的长度和原数据框的行数相等。而且索引和原数据框或者序列的索引保持一致。
data1["年龄"].groupby(data1["性别"]).transform(np.mean)

数据透视表
pivot_table1=data1.pivot_table(values=["年龄","受教育程度"],index=["地域编码","性别"],aggfunc={"年龄":[np.mean,np.max],"受教育程度":np.mean})

变量与索引的相互转 列变成索引
data1.set_index(["pid"],drop=False) #drop 参数是要不要将变成索引的列从columns中删掉。 #这个方法有inplace参数

索引变成列
temp=data1.set_index(['fid','pid'],drop=True) #temp表示把它存为临时数据框,不影响原数据框 temp.reset_index()#变成原数据框 #索引变成新的一列,列名index temp.reset_index().reset_index()

将数值变量进行离散化处理 【Python|python中的pandas库】有时候,我们会碰到这样的需求,想要将年龄进行离散化(分桶,分箱),直白来说就是将年龄分成几个区间,这里我们想要将年龄分成 3 个区间段。就可以使用 Pandas 的 cut 方法来完成
pd.cut
pd.cut(data1["年龄"],3) #其他方法 np.linspace(data1.年龄.min(),data1.年龄.max(),4) #自定义标签 data1["年龄段"]=pd.cut(data1.年龄, [0,45, 59, 74, 89,120],labels=["青年", "中年", "老年前期","老年","长寿老人"])

pd.qcut:用分位数进行分箱
pd.qcut(data1["年龄"],4,labels=[1,2,3,4])

将分类变量转化为虚拟变量(pd.get_dummies)
pd.get_dummies(data1["性别"],prefix="性别") #你还可以尝试下面的这个命令,把虚拟变量变成两列和data1合并 #pd.get_dummies(data1,prefix="性别",columns=["性别"])

数据框对象的复制
data1=pd.DataFrame(np.random.rand(4,3),columns=["x1","x2","x3"]) #浅复制,一个改变,另一个也会改变。 data2=data1 print(id(data1),id(data2)) #深复制,单独改变一方,另一方不受影响 data3=data1.copy(deep=True) print(id(data1),id(data3))

字符串变量的常用方法
data1.fid.str.len()#计算字符串的长度 data1.fid.str.replace("f","a") #对字符串变量进行查找替换 data1.fid.str.count("0")#计算字符串出现次数。 data1.pid.astype(str).str.zfill(5) #填补字符串 series1=pd.Series(["湖北省武汉市","四川省成都市","河南省郑州市"]) #正则表达式匹配。 series1.str.extract(r"(.+省)")

删除重复项
data1.duplicated() # duplicated()判断是否是重复的项,返回的是布尔值 #subset参数指定列,keep参数='first' data2 = data1.drop_duplicates() # drop_duplicates()移除重复的项,只保留第一次出现的项 #这个方法有inplace参数

数据抽样
data1=pd.DataFrame(np.random.rand(100,3),columns=['x1','x2','x3']) data1.sample(frac=0.1) #设定了抽取样本比例为10%,所以抽去了10行 #sample(n=None, frac=None, replace=False, weights=None,random_state=None, axis=None) #replace=False表示无放回抽样 #random_state是设定随机种子,保证每次运行代码抽取到的样本一样

日期时间变量的处理
#导入相关的库 import time import datetime

时间戳Timestamp对象的生成
import pandas as pd #有如下两种方法 pd.Timestamp() pd.to_datetime()

pd.Timestamp 传入一个字符串
pd.Timestamp('2017/01/10') '''这里要求字符串不能是一个特别乱没有规律的字符串, 因为这个函数没有format参数'''

传入一个数字
pd.Timestamp(1, unit='s', tz='Asia/Shanghai') #根据距离纪元的秒数生成时间戳(可设定时区) #根据距离纪元的秒数生成指定时区的时间,默认是0时区。

传入多个日期元素
pd.Timestamp(1970, 1, 1,12) pd.Timestamp(year=2017, month=1, day=1, hour=12)

传入一个datetime实例
pd.Timestamp(pd.datetime(2014,1,1))

pd.to_datetime 传入字符串
pd.to_datetime("2018/10/03",format="%Y/%m/%d",errors="ignore") #errors有raise,ignore,coerce

传入数值
pd.to_datetime(1,unit="s") #这个参数没有tz参数,不能设定时区,只能返回0时区时间 #pd.Timestamp(1, unit='s')这个命令和上面的命令结果一样

传入一个datetime实例
pd.to_datetime(pd.datetime(2014,1,1))

获取当前时间
#获取当前时间 pd.datetime.now() datetime.datetime.now() #上面这两句命令的结果是一样的都会返回一个datetime实例

时间戳实例的属性和方法
import pandas as pd a=pd.Timestamp("1970/1/1T00:01:20") a.year#调取年 1970 a.month #调取月 1 a.day #调取日 1 a.hour #调取时间里面的小时 a.minute#调取时间里面的分1 a.second#调取时间里面的秒20 a.dayofweek #调取星期几 a.date()#日期调出来 a.time()#时间调出来 a.timestamp() #返回距离纪元的秒数。 a.value#返回距离纪元的纳秒数。 a.strftime("%m/%d/%Y")#将Timestamp变成指定格式的字符串。 a.strftime("%A") #英文星期几

计算时差Timedelta实例
#两个Timestamp对象相减产生时间差 a=pd.Timestamp("2019/7/12T13:48:00") b=pd.Timestamp("2019/7/12T9:48:00") d=a-b #d时间差对象的类型是Timedelta #直接生成一个Timedelta 时间差 cd = pd.Timedelta(days=6, minutes=50, seconds=3,milliseconds=10, microseconds=9, nanoseconds=12) print(cd)

生成时间戳范围
s1=pd.date_range('2011-1-20',freq='D',periods=8) #s1是一个日期时间序列 s1[0] #类型为Timestamp

数据框里面对时间变量的操作 日期时间变量转化为指定格式的字符串变量
#方法1 data1["date"].dt.strftime("%m/%d/%Y") #方法2 data1["datestr"]=data1["date"].map(lambda x:x.strftime("%m/%d/%Y"))

如何把日期时间变量的各个元素调出来
data1["date"].dt.year #把年调出来是一个int类型 data1["date"].dt.month #把月调出来是一个int类型 data1["date"].dt.day #把日调出来是一个int类型 data1["date"].dt.date #把时间调出来,是一个object类型 data1["date"].dt.time #把时间调出来,是一个object类型

如何把年月日时间变成年月时间
data1["date"].dt.to_period(freq="M")

如何根据多个元素合成一个日期时间变量
data1.apply(lambda x:pd.Timestamp(x["year"],x["month"],x["day"]),axis=1)

字符串变量转化为日期时间变量
#方法1 pd.to_datetime(data1["datestr"],format="%m/%d/%Y",errors="ignore") #方法2 data1["datestr"].map(lambda x:pd.Timestamp(x)) #方法3 data1["datestr"].map(lambda x:pd.to_datetime(x,format="%m/%d/%Y"))

数值变量转化为日期时间变量
#方法1 pd.to_datetime(data1["num"],unit="s") #方法2 data1["num"].map(lambda x:pd.to_datetime(x,unit='s')) #方法3 data1["num"].map(lambda x:pd.Timestamp(x,unit='s'))

时间差运算
data1["date"]+pd.Timedelta(days=1)

如何求变量的滞后一期
#求变量的滞后一期 data1["p"].shift(1) #求变量的先导一期 data1["p"].shift(-1).tail()

日期时间变量用做数据框的索引 定义索引
data1.index=data1["date"] data1["week"]=data1.index.dayofweek+1 ##用这个算出来星期1用0表示,所以最好加上1

索引和切片
#下面这几种切片和索引方式都是可以的 data1["p"]["2003-1-06"] data1["p"]["2003-2"] data1["p"]['2003-1-06':'2003-1-10'] data1[(data1.index>"2003-1-6") & (data1.index<"2003-1-15")]

日期频率的转换
index = pd.date_range('2016', periods=1000, freq='D') test=pd.DataFrame(np.random.randint(3,10,(1000,3)),index) test_new=test.asfreq(freq='5D')#由高频向低频转化 test_new.asfreq(freq='D').head(6) #由低频向高频转化 test_new.asfreq('D', method='pad').head(6) #"pad"是向后填充的方法

    推荐阅读