08_Pandas数据重塑与透视

数据透视

数据透视表,可以找出大量复杂无关数据的内在关系,将数据转换为有意义、有价值的信息。

整理透视

基础的透视操作,可以使用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')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值