数据透视
数据透视表,可以找出大量复杂无关数据的内在关系,将数据转换为有意义、有价值的信息。
整理透视
基础的透视操作,可以使用df.pivot()返回按给定的索引、列值,重新组织整理后的DataFrame。df.pivot()有三个参数
- index:作为新DataFrame的索引,取分组去重的值;如果不传入,则取现有的索引
- columns:作为新DataFrame的索引,取去重的值,当列和索引的组合有多个值时会报错,需要使用pd.pivot_table()进行操作
- values:作为新DataFrame的值,如果指定多个,会形成多层索引;如果不指定会默认为所有剩余列
df = pd.DataFrame({
'A':['a1','a1','a2','a3','a3','a3'],
'B':['b1','b2','b3','b1','b2','b3'],
'C':['c1','c2','c3','c4','c5','c6'],
'D':['d1','d2','d3','d4','d5','d6']
})
# 透视、指定索引、列、值
df.pivot(index='A',columns='B',values='C')
# 不指定内容值
df.pivot(index='A',columns='B')
# 指定多列
df.pivot(index='A',columns='B',values=['C','D'])
聚合透视
df.pivot()只是对原数据的结构,显示形式做了变换,在实现业务中,往往还需要在数据透视过程中对值进行计算。pd.pivot_table():可以实现类似Excel那样的高级数据透视功能。
pd.pivot_table()有以下几个关键参数
- data:要透视的DataFrame对象
- index:在数据透视表索引上进行分组的列
- values:要聚合的一列或多列
- columns:在数据透视表列上进行分组的列
- aggfunc:用于聚合的函数,默认是平均数mean
- fill_value:透视会以空值填充值
- margins:是否增加汇总行列
# 构造数据
df = pd.DataFrame({
'A':['a1','a1','a1','a2','a2','a2'],
'B':['b2','b2','b1','b1','b1','b1'],
'C':['c1','c1','c2','c2','c1','c1'],
'D':[1,2,3,4,5,6]
})
# 透视:以A为索引,以B为列
pd.pivot_table(df,index='A',columns='B',values='D')
# 复杂一点的透视
pd.pivot_table(df,index=['A','B'],
columns=['C'],
values='D',
aggfunc=np.sum,
fill_value=0,
margins=True)
pd.pivot_table(df,index=['A','B'],
columns=['C'],
values='D',
aggfunc=[np.sum,np.mean])
# 如果有多个数据列,可以为每一列指定不同的聚合方法
df = pd.DataFrame({
'A':['a1','a1','a1','a2','a2','a2'],
'B':['b2','b2','b1','b1','b1','b1'],
'C':['c1','c1','c2','c2','c1','c1'],
'D':[1,2,3,4,5,6],
'E':[9,8,7,4,5,6]
})
pd.pivot_table(df,index=['A','B'],
columns=['C'],
aggfunc={'D':np.sum,'E':np.mean})
数据堆叠
在多层索引的数据中,通常为了方便查看、对比,会将所有数据呈现在一列中;相反,对于层级过多的数据,我们可以实施解堆操作,让它呈现多列的状态。
数据堆叠可以简单的理解成将多列数据转为一列数据。如果原始数据有多个数据列,堆叠(stack)的过程表示将这些数据列的所有数据表全部旋转的行上。类似地,解堆(unstack)的过程表示将在行上的索引旋转到列上。
- 堆叠:“透视”某个级别的(可能是多层的)列标签,返回带有索引的DataFrame。该索引带有一个新的行标签,这个新标签在原有索引的最右边
- 解堆:将(可能是多册的)行索引的某个级别“透视”到列轴,从而生成具有新的最里面的列标签级别的重构的DataFrame。
堆叠操作df.stack()
# 构造数据
df = pd.DataFrame({
'A':['a1','a1','a2','a2'],
'B':['b1','b2','b1','b2'],
'C':[1,2,3,4],
'D':[5,6,7,8],
'E':[5,6,7,8]
})
# 设置索引
df.set_index(['A','B'],inplace=True)
# 堆叠
df.stack()
type(df.stack()) # 查看类型 是一个Series,所有的列都透视在了多层索引的新增列中
解堆操作
s = df.stack()
s.unstack() # 生成一个DataFrame
交叉表
交叉表(cross tabulation)是一个很有用的分析工具,是用于统计分组频率的特殊透视表。简单说:交叉表就是将两列或多列中不重复的元素组成一个新的DataFrame,新数据的行和列交叉部分的值为其组合在原数据中的数量。
# 基本语法
pd.crosstab(index,columns,values=None,rownames=None,
colnames=None,aggfunc=None,margins=False,
margins_name:str='All',dropna:bool=True,
normalize=False)
- index:传入列,例如df[“A”],作为新数据的索引
- columns:传入列,作为新数据的列,新数据的列为此列的去重值
- values:可选,传入列,根据此列的数值进行计算,计算方法取aggfunc参数指定的方法,此时aggfunc为必传
- aggfunc:函数,valuses列计算使用的计算方法
- rownames:新数据和行名,一个序列,默认值为None,必须与传递的行数,组数匹配
- colnames:新数据和列名,一个序列,默认值为None,必须与传递的列数,组数匹配
- margins:bool值,默认为False,添加行/列边距(小记)
- normalize:{‘all’,‘index’,‘columns’} 或者{0,1},默认值为False(0)。通过将所有的值除以值得总和进行归一化。
生成交叉表
# 构造数据
df = pd.DataFrame({
'A':['a1','a1','a2','a2','a1'],
'B':['b2','b1','b2','b2','b1'],
'C':[1,2,3,4,5]
})
# 生成交叉表
pd.crosstab(df['A'],df['B'])
# 对分类数据做交叉
one = pd.Categorical(['a','b'],categories=['a','b','c'])
two = pd.Categorical(['d','e'],categories=['d','e','f'])
pd.crosstab(one,tow)
## 归一化
normalize参数可以帮助我们实现数据归一化,算法为对应值除以所有值的总和,让数据处于0~1的范围,方便观察此位置上的数据在全体中的地位
# 归一化
pd.crosstab(df['A'],df['B'],normalize=True)
# 交叉表,按列归一化(每一列单独计算占比)
pd.crosstab(df['A'],df['B'],normalize='columns')
指定集合方法
用aggfunc指定聚合方法,对values指定的列进行计算
pd.crosstab(df['A'],df['B'],aggfunc=np.sum,values=df['C'])
汇总
margins=True可以增加行和列的汇总,按照行列方向对数据求和,类似margins_name='total’可以定义这个汇总行和列的名称
pd.crosstab(df['A'],df['B'],
values=df['C'],
aggfunc=np.sum,
margins=True,
margins_name='sum')
数据融合
数据融合df.melt()是df.privot()的逆操作函数,它是将指定的列铺开,放到行上名为variable(可指定),值为value(可指定)列。
pd.melt(frame:pandas.core.frame.DataFrame,
id_vars=None,value_vars=None,
var_names='variable',value_name='value',
col_level=None)
- id_vars:tuple、list或ndarray(可选),用作标识变量的列
- value_vars:tuple、list或ndarray(可选),要取消透视的列。如果未指定,则使用未设定的id_vars的所有列
- var_name:scalar,用于“变量”列的名称。如果为None,则使用frame.columns.name或“variable”。
- value_name:scalar,默认为“value”,用于‘value“列的名称
- col_level:int或str(可选),如果列是多层索引,则使用此级别来融合
# 原数据
df = pd.DataFrame({
'A':['a1','a2','a3','a4','a5'],
'B':['b1','b2','b3','b4','b5'],
'C':[1,2,3,4,5]
})
# 数据融合
pd.melt(df)
# 以上操作将A、B、C三列的标识和值展开,一列为标签,默认列名为variable,另一列为值,默认列名为value
数据融合时,可以指定标识,下列指定A、B两列作为融合操作后的表示,保持不变,对其余列(C列)展开数据
# 数据融合,指定标识
pd.melt(df,id_vars=['A','B'])
#数据融合,指定值列
pd.melt(df,value_vars=['B','C'])
标识的名称和值的名称默认分别是variable和value,可以指定它们的名称
pd.melt(df,id_vars=['A'],value_vars=['B'],
var_name='B_lable',value_name='B_value')
虚拟变量
虚拟变量(Dummy Variable),是一种用来反映质的属性的人工变量,是量化了的自变量,通常取值为0或1。
生成虚拟变量的方法pd.get_dummies()是将一列或多列的去重值作为新表的列,每列的值由0和1组成:如果原来位置的值与列名相同,则在新表中该位置的值为1,否则为0。
pd.get_dummies(data,prefix=None,
prefix_sep='_',dummy_na=False,
columns=None,sparse=False,
drop_first=False,dtype=None)
- data:被操作的数据,DataFrame或者Series。
- prefix:新列的前缀
- prefix_sep:新列前缀的连接符
# 原数据
df = pd.DataFrame({'a':list('adcb'),
'b':list('fehg'),
'a1':range(4),
'b1':range(4,8)})
# 生成虚拟变量
pd.get_dummies(df.a)
# 只关注df.a列:a列共有a、b、c、d四个值,故新数据有次四列;索引和列名交叉的位置如果是1,说明此索引位置上的值为列名,为0则表示不是列名。
使用prefix定义列名前缀
pd.get_dummies(df['a1'],prefix='a1')
可以直接对DataFrame生成虚拟变量,会将所有非数字列生成虚拟变量(数字列保持不变)
# 生成虚拟变量
pd.get_dummies(df)
#只生成b列的虚拟变量
pd.get_dummies(df,columns=['b'])
因子化
因子化是指将一个存在大量重复的一维数据解析成枚举值得过程。可以使用pd.factorize()、Series.factorize()、Index.factorize()方法。
# 数据
data=['b','b','c','a','b']
# 因子化
codes,uniques = pd.factorize(data)
# 编码
codes
# 去重值
uniques
- codes:array类型。数字编码表,将第一个元素编为0,其次依次用1、2等,遇到相同元素使用相同编码。
- uniques:array类型。去重值,就是因子
使用sort=True参数,将对唯一值进行排序,编码列表将继续与原值保持对应关系
codes,uniques = pd.factorize(data,sort=True)
codes
uniques
缺失值不会出现在唯一值列表,在编码中将为-1
codes,uniques = pd.factorize(['b',None,'c','a','b'],sort=True)
codes
uniques
pandas的枚举类型数据(Categorical)也可以使用此方法
cat = pd.Categorical(['a','a','c'],categories=['a','b','c'])
codes,uniques = pd.factorize(cat)
codes
uniques
explode List
将类似列表的每个元素转换为一行,索引值是相同的。
# 原始数据
s = pd.Series([[1,2,3],'foo',[],[3,4]])
s.explode()
# 每行列表中的元素都独自占用了—行,索引保持不变,空列表值变成了NaN,非列表的元素没有变化。
DataFrame 中使用explode
df = pd.DataFrame({'A':[[1,2,3],'foo',[],[3,4]],'B':range(4)})
df.explode('A')
# DataFrame指定列名后,其他列的值保持不变
对于非列表数据,也可以处理之后让其完成explode
df = pd.DataFrame([{'var1':'a,b,c','var2':1},{'var1':'d,e,f','var2':2}])
df.assign(var1=df.var1.str.split(',')).explode('var1')