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"是向后填充的方法
推荐阅读
- Python|pandas操作指南(超级详细!!!)
- sklearn实战|sklearn实战之数据预处理与特征工程
- python机器学习与数据挖掘|数据预处理(七)——利用sklearn进行数据预处理
- 数据分析|Python 疫情数据的可视化与分析(二)
- 抖音解析|短视频搬运软件(抖音批量解析下载一个作者所有视频)
- 大数据可视化|Python疫情数据可视化分析+数据预测(pandas+pyecharts+statsmodels+matplotlib+sql)
- HaaS解决方案|看屏幕眼睛干(没问题 用ESP32和 HaaS Python做一个 全自动加湿器)
- HaaS解决方案|开工大吉,ESP32 + HaaS Python为您送上久坐提醒器,好好工作更要注意健康哦
- HaaS解决方案|用ESP32打造一个物联网红外测温打卡机/春节结束急着上班(哒咩,再努力奋斗也要先测体温)