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将列转化为float

data1["身高"].astype(str).astype(float) 
#当列里有非数值字符串时,运行会出错
#字符串是"nan",用astype,转化为float,会变成缺失值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={"性别":"","身高":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是设定右表的连接变量。 suffixes是设定重复列的变量名后缀,以便知道重复列来自哪张表

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()

将数值变量进行离散化处理

有时候,我们会碰到这样的需求,想要将年龄进行离散化(分桶,分箱),直白来说就是将年龄分成几个区间,这里我们想要将年龄分成 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"是向后填充的方法

你可能感兴趣的:(Python,Python基础)