当前位置: 首页 > 知识库问答 >
问题:

如何透视数据帧?

陆宇航
2023-03-14
  • 什么是透视?
  • 如何透视?
  • 这是枢轴吗?
  • 长格式到宽格式?

我见过很多关于透视表的问题。即使他们不知道他们询问的是透视表,他们通常也是。几乎不可能写出一个包含旋转的所有方面的规范的问题和答案。

...但我要试一试。

现有问题和答案的问题是,问题通常集中在一个细微差别上,而OP很难将其概括出来,以便使用现有的许多好答案。然而,没有一个答案试图给出一个全面的解释(因为这是一个令人生畏的任务)

从我的谷歌搜索中看几个例子

  1. 如何在Pandas中透视数据帧?
  • 好的问答。但答案只回答了具体的问题,很少解释。
  • 在这个问题中,OP与枢轴的输出有关。即列的外观。OP希望它看起来像R。这对pandas用户没有太大帮助。
  • 另一个不错的问题,但答案集中在一个方法上,即pd.dataframe.pivot

因此,每当有人搜索pivot时,他们会得到零星的结果,这些结果很可能无法回答他们的特定问题。

您可能会注意到,我给我的列和相关的列值命名得很明显,以与我将在下面的答案中如何枢轴相对应。

import numpy as np
import pandas as pd
from numpy.core.defchararray import add

np.random.seed([3,1415])
n = 20

cols = np.array(['key', 'row', 'item', 'col'])
arr1 = (np.random.randint(5, size=(n, 4)) // [2, 1, 2, 1]).astype(str)

df = pd.DataFrame(
    add(cols, arr1), columns=cols
).join(
    pd.DataFrame(np.random.rand(n, 2).round(2)).add_prefix('val')
)
print(df)

     key   row   item   col  val0  val1
0   key0  row3  item1  col3  0.81  0.04
1   key1  row2  item1  col2  0.44  0.07
2   key1  row0  item1  col0  0.77  0.01
3   key0  row4  item0  col2  0.15  0.59
4   key1  row0  item2  col1  0.81  0.64
5   key1  row2  item2  col4  0.13  0.88
6   key2  row4  item1  col3  0.88  0.39
7   key1  row4  item1  col1  0.10  0.07
8   key1  row0  item2  col4  0.65  0.02
9   key1  row2  item0  col2  0.35  0.61
10  key2  row0  item2  col1  0.40  0.85
11  key2  row4  item1  col2  0.64  0.25
12  key0  row2  item2  col3  0.50  0.44
13  key0  row4  item1  col4  0.24  0.46
14  key1  row3  item2  col3  0.28  0.11
15  key0  row3  item1  col1  0.31  0.23
16  key0  row0  item2  col3  0.86  0.01
17  key0  row4  item0  col3  0.64  0.21
18  key2  row2  item2  col0  0.13  0.45
19  key0  row2  item0  col4  0.37  0.70

>

  • 为什么我获得值错误:索引包含重复的条目,无法重塑

    如何透视df以使col值为列,row值为索引,val0的均值为值?

     col   col0   col1   col2   col3  col4
     row                                  
     row0  0.77  0.605    NaN  0.860  0.65
     row2  0.13    NaN  0.395  0.500  0.25
     row3   NaN  0.310    NaN  0.545   NaN
     row4   NaN  0.100  0.395  0.760  0.24
    

    如何透视df以使col值为列,row值为索引,val0的平均值为值,丢失的值为0

     col   col0   col1   col2   col3  col4
     row                                  
     row0  0.77  0.605  0.000  0.860  0.65
     row2  0.13  0.000  0.395  0.500  0.25
     row3  0.00  0.310  0.000  0.545  0.00
     row4  0.00  0.100  0.395  0.760  0.24
    

    我能得到mean以外的东西吗,比如sum

     col   col0  col1  col2  col3  col4
     row                               
     row0  0.77  1.21  0.00  0.86  0.65
     row2  0.13  0.00  0.79  0.50  0.50
     row3  0.00  0.31  0.00  1.09  0.00
     row4  0.00  0.10  0.79  1.52  0.24
    

    我可以一次做更多的聚合吗?

            sum                          mean                           
     col   col0  col1  col2  col3  col4  col0   col1   col2   col3  col4
     row                                                                
     row0  0.77  1.21  0.00  0.86  0.65  0.77  0.605  0.000  0.860  0.65
     row2  0.13  0.00  0.79  0.50  0.50  0.13  0.000  0.395  0.500  0.25
     row3  0.00  0.31  0.00  1.09  0.00  0.00  0.310  0.000  0.545  0.00
     row4  0.00  0.10  0.79  1.52  0.24  0.00  0.100  0.395  0.760  0.24
    

    我可以聚合多个值列吗?

           val0                             val1                          
     col   col0   col1   col2   col3  col4  col0   col1  col2   col3  col4
     row                                                                  
     row0  0.77  0.605  0.000  0.860  0.65  0.01  0.745  0.00  0.010  0.02
     row2  0.13  0.000  0.395  0.500  0.25  0.45  0.000  0.34  0.440  0.79
     row3  0.00  0.310  0.000  0.545  0.00  0.00  0.230  0.00  0.075  0.00
     row4  0.00  0.100  0.395  0.760  0.24  0.00  0.070  0.42  0.300  0.46
    

    可以按多列细分吗?

     item item0             item1                         item2                   
     col   col2  col3  col4  col0  col1  col2  col3  col4  col0   col1  col3  col4
     row                                                                          
     row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.605  0.86  0.65
     row2  0.35  0.00  0.37  0.00  0.00  0.44  0.00  0.00  0.13  0.000  0.50  0.13
     row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.000  0.28  0.00
     row4  0.15  0.64  0.00  0.00  0.10  0.64  0.88  0.24  0.00  0.000  0.00  0.00
    

     item      item0             item1                         item2                  
     col        col2  col3  col4  col0  col1  col2  col3  col4  col0  col1  col3  col4
     key  row                                                                         
     key0 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.86  0.00
          row2  0.00  0.00  0.37  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.50  0.00
          row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.00  0.00  0.00
          row4  0.15  0.64  0.00  0.00  0.00  0.00  0.00  0.24  0.00  0.00  0.00  0.00
     key1 row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.81  0.00  0.65
          row2  0.35  0.00  0.00  0.00  0.00  0.44  0.00  0.00  0.00  0.00  0.00  0.13
          row3  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.28  0.00
          row4  0.00  0.00  0.00  0.00  0.10  0.00  0.00  0.00  0.00  0.00  0.00  0.00
     key2 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.40  0.00  0.00
          row2  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.13  0.00  0.00  0.00
          row4  0.00  0.00  0.00  0.00  0.00  0.64  0.88  0.00  0.00  0.00  0.00  0.00
    

    我能聚合列和行一起出现的频率吗,也就是“交叉制表”?

     col   col0  col1  col2  col3  col4
     row                               
     row0     1     2     0     1     1
     row2     1     0     2     1     2
     row3     0     1     0     2     0
     row4     0     1     2     2     1
    

    我如何通过只在两列上枢转来将数据帧从长转换为宽?考虑到这一点,

    np.random.seed([3, 1415])
    df2 = pd.DataFrame({'A': list('aaaabbbc'), 'B': np.random.choice(15, 8)})        
    df2        
       A   B
    0  a   0
    1  a  11
    2  a   2
    3  a  11
    4  b  10
    5  b  10
    6  b  14
    7  c   7
    

    预期的应该类似于

          a     b    c
    0   0.0  10.0  7.0
    1  11.0  10.0  NaN
    2   2.0  14.0  NaN
    3  11.0   NaN  NaN
    

    pivot之后,如何将多索引扁平化为单索引

       1  2   
       1  1  2        
    a  2  1  1
    b  2  1  0
    c  1  0  0
    

       1|1  2|1  2|2               
    a    2    1    1
    b    2    1    0
    c    1    0    0
    
  • 共有2个答案

    钱钊
    2023-03-14

    扩展@PirSquared的答案是问题10的另一个版本

    数据帧:

    d = data = {'A': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 3, 6: 5},
     'B': {0: 'a', 1: 'b', 2: 'c', 3: 'a', 4: 'b', 5: 'a', 6: 'c'}}
    df = pd.DataFrame(d)
    
       A  B
    0  1  a
    1  1  b
    2  1  c
    3  2  a
    4  2  b
    5  3  a
    6  5  c
    

    输出:

       0     1     2
    A
    1  a     b     c
    2  a     b  None
    3  a  None  None
    5  c  None  None
    

    使用df.groupbypd.series.tolist

    t = df.groupby('A')['B'].apply(list)
    out = pd.DataFrame(t.tolist(),index=t.index)
    out
       0     1     2
    A
    1  a     b     c
    2  a     b  None
    3  a  None  None
    5  c  None  None
    

    或者使用pd.pivot_tabledf.squeze.的更好的替代方案

    t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
    out = pd.DataFrame(t.tolist(),index=t.index)
    
    公孙辰龙
    2023-03-14

    我们从回答第一个问题开始:

    为什么我得到valueerror:索引包含重复的条目,无法重塑

    这是因为pandas试图用重复的条目重新索引columnsindex对象。可以使用不同的方法来执行透视。其中一些不太适合于当有重复的键时,它被要求以其为中心。例如。请考虑pd.dataframe.pivot。我知道有重复的条目共享rowcol值:

    df.duplicated(['row', 'col']).any()
    
    True
    

    因此当我pivot使用

    df.pivot(index='row', columns='col', values='val0')
    

    我得到了上面提到的错误。事实上,当我尝试执行相同的任务时,我会得到相同的错误:

    df.set_index(['row', 'col'])['val0'].unstack()
    

    下面是我们可以用来透视的习语列表

    • pd.dataframe.groupby+pd.dataframe.unstack
      • 执行任何类型透视的良好通用方法
      • 您可以通过指定将构成一个组中的透视行级别和列级别的所有列。然后选择要聚合的剩余列和要执行聚合的函数。最后,您unstack要在列索引中的级别。
      • 具有更直观API的groupby的美化版本。对于许多人来说,这是首选的做法。也是开发人员希望采用的方法。
      • 指定行级别、列级别、要聚合的值以及要执行聚合的函数。
      • 对一些人(包括我自己)来说是方便和直观的。无法处理重复的分组密钥。
      • groupby范例类似,我们指定最终将是行或列级别的所有列,并将这些列设置为索引。然后,我们unstack列中需要的级别。如果剩余的索引级别或列级别不唯一,则此方法将失败。
      • set_index非常相似,因为它共享重复密钥限制。API也非常有限。它只对索引采用标量值。
      • pivot_table方法类似,我们选择要透视的行、列和值。但是,我们无法聚合,如果行或列不唯一,则此方法将失败。
      • 这是pivot_table的专用版本,以其最纯粹的形式是执行几个任务的最直观的方式。
      • 这是一种非常隐晦但速度非常快的高度先进的技术。它不可能在所有情况下都使用,但当它可以使用并且您使用得很舒服时,您将获得性能奖励。
      • 我用它巧妙地执行交叉制表。

      对于后续的每个答案和问题,我要做的是使用pd.dataframe.pivot_table来回答它。然后我将提供执行相同任务的替代方案。

      如何透视df以使col值为列,row值为索引,val0的平均值为值,丢失的值为0

      >

    • pd.dataframe.pivot_table

      > 默认情况下不设置

    • fill_value。我倾向于适当地设置。在本例中,我将其设置为0。注意,我跳过了问题2,因为它与没有fill_value
    • 的答案相同
    • aggfunc='mean'是默认值,我不必设置它。我把它写进去是为了明确。

      df.pivot_table(
          values='val0', index='row', columns='col',
          fill_value=0, aggfunc='mean')
      
      col   col0   col1   col2   col3  col4
      row                                  
      row0  0.77  0.605  0.000  0.860  0.65
      row2  0.13  0.000  0.395  0.500  0.25
      row3  0.00  0.310  0.000  0.545  0.00
      row4  0.00  0.100  0.395  0.760  0.24
      

      PD.DataFrame.GroupBy

      df.groupby(['row', 'col'])['val0'].mean().unstack(fill_value=0)
      

      pd.crosstab

      pd.crosstab(
          index=df['row'], columns=df['col'],
          values=df['val0'], aggfunc='mean').fillna(0)
      

      我能得到mean以外的东西吗,比如sum

      >

    • pd.dataframe.pivot_table

      df.pivot_table(
          values='val0', index='row', columns='col',
          fill_value=0, aggfunc='sum')
      
      col   col0  col1  col2  col3  col4
      row                               
      row0  0.77  1.21  0.00  0.86  0.65
      row2  0.13  0.00  0.79  0.50  0.50
      row3  0.00  0.31  0.00  1.09  0.00
      row4  0.00  0.10  0.79  1.52  0.24
      

      PD.DataFrame.GroupBy

      df.groupby(['row', 'col'])['val0'].sum().unstack(fill_value=0)
      

      pd.crosstab

      pd.crosstab(
          index=df['row'], columns=df['col'],
          values=df['val0'], aggfunc='sum').fillna(0)
      

      我可以一次做更多的聚合吗?

      注意,对于pivot_tablecrosstab,我需要传递调用列表。另一方面,groupby.agg能够为有限数量的特殊函数获取字符串。groupby.agg也会采用我们传递给其他人的相同的调用,但使用字符串函数名通常更有效,因为这样可以提高效率。

      >

    • pd.dataframe.pivot_table

      df.pivot_table(
          values='val0', index='row', columns='col',
          fill_value=0, aggfunc=[np.size, np.mean])
      
           size                      mean                           
      col  col0 col1 col2 col3 col4  col0   col1   col2   col3  col4
      row                                                           
      row0    1    2    0    1    1  0.77  0.605  0.000  0.860  0.65
      row2    1    0    2    1    2  0.13  0.000  0.395  0.500  0.25
      row3    0    1    0    2    0  0.00  0.310  0.000  0.545  0.00
      row4    0    1    2    2    1  0.00  0.100  0.395  0.760  0.24
      

      PD.DataFrame.GroupBy

      df.groupby(['row', 'col'])['val0'].agg(['size', 'mean']).unstack(fill_value=0)
      

      pd.crosstab

      pd.crosstab(
          index=df['row'], columns=df['col'],
          values=df['val0'], aggfunc=[np.size, np.mean]).fillna(0, downcast='infer')
      

      我可以聚合多个值列吗?

      >

    • pd.dataframe.pivot_table我们传递values=['val0','val1']但我们本可以完全关闭它

      df.pivot_table(
          values=['val0', 'val1'], index='row', columns='col',
          fill_value=0, aggfunc='mean')
      
            val0                             val1                          
      col   col0   col1   col2   col3  col4  col0   col1  col2   col3  col4
      row                                                                  
      row0  0.77  0.605  0.000  0.860  0.65  0.01  0.745  0.00  0.010  0.02
      row2  0.13  0.000  0.395  0.500  0.25  0.45  0.000  0.34  0.440  0.79
      row3  0.00  0.310  0.000  0.545  0.00  0.00  0.230  0.00  0.075  0.00
      row4  0.00  0.100  0.395  0.760  0.24  0.00  0.070  0.42  0.300  0.46
      

      PD.DataFrame.GroupBy

      df.groupby(['row', 'col'])['val0', 'val1'].mean().unstack(fill_value=0)
      

      可以按多列细分吗?

      >

    • pd.dataframe.pivot_table

      df.pivot_table(
          values='val0', index='row', columns=['item', 'col'],
          fill_value=0, aggfunc='mean')
      
      item item0             item1                         item2                   
      col   col2  col3  col4  col0  col1  col2  col3  col4  col0   col1  col3  col4
      row                                                                          
      row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.605  0.86  0.65
      row2  0.35  0.00  0.37  0.00  0.00  0.44  0.00  0.00  0.13  0.000  0.50  0.13
      row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.000  0.28  0.00
      row4  0.15  0.64  0.00  0.00  0.10  0.64  0.88  0.24  0.00  0.000  0.00  0.00
      

      PD.DataFrame.GroupBy

      df.groupby(
          ['row', 'item', 'col']
      )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
      

      可以按多列细分吗?

      >

    • pd.dataframe.pivot_table

      df.pivot_table(
          values='val0', index=['key', 'row'], columns=['item', 'col'],
          fill_value=0, aggfunc='mean')
      
      item      item0             item1                         item2                  
      col        col2  col3  col4  col0  col1  col2  col3  col4  col0  col1  col3  col4
      key  row                                                                         
      key0 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.86  0.00
           row2  0.00  0.00  0.37  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.50  0.00
           row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.00  0.00  0.00
           row4  0.15  0.64  0.00  0.00  0.00  0.00  0.00  0.24  0.00  0.00  0.00  0.00
      key1 row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.81  0.00  0.65
           row2  0.35  0.00  0.00  0.00  0.00  0.44  0.00  0.00  0.00  0.00  0.00  0.13
           row3  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.28  0.00
           row4  0.00  0.00  0.00  0.00  0.10  0.00  0.00  0.00  0.00  0.00  0.00  0.00
      key2 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.40  0.00  0.00
           row2  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.13  0.00  0.00  0.00
           row4  0.00  0.00  0.00  0.00  0.00  0.64  0.88  0.00  0.00  0.00  0.00  0.00
      

      PD.DataFrame.GroupBy

      df.groupby(
          ['key', 'row', 'item', 'col']
      )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
      

      pd.dataframe.set_index因为这组键对于行和列都是唯一的

      df.set_index(
          ['key', 'row', 'item', 'col']
      )['val0'].unstack(['item', 'col']).fillna(0).sort_index(1)
      

      我能聚合列和行一起出现的频率吗,也就是“交叉制表”?

      >

    • pd.dataframe.pivot_table

      df.pivot_table(index='row', columns='col', fill_value=0, aggfunc='size')
      
          col   col0  col1  col2  col3  col4
      row                               
      row0     1     2     0     1     1
      row2     1     0     2     1     2
      row3     0     1     0     2     0
      row4     0     1     2     2     1
      

      PD.DataFrame.GroupBy

      df.groupby(['row', 'col'])['val0'].size().unstack(fill_value=0)
      

      pd.crosstab

      pd.crosstab(df['row'], df['col'])
      

      PD.Factorize+NP.bincount

      # get integer factorization `i` and unique values `r`
      # for column `'row'`
      i, r = pd.factorize(df['row'].values)
      # get integer factorization `j` and unique values `c`
      # for column `'col'`
      j, c = pd.factorize(df['col'].values)
      # `n` will be the number of rows
      # `m` will be the number of columns
      n, m = r.size, c.size
      # `i * m + j` is a clever way of counting the 
      # factorization bins assuming a flat array of length
      # `n * m`.  Which is why we subsequently reshape as `(n, m)`
      b = np.bincount(i * m + j, minlength=n * m).reshape(n, m)
      # BTW, whenever I read this, I think 'Bean, Rice, and Cheese'
      pd.DataFrame(b, r, c)
      
            col3  col2  col0  col1  col4
      row3     2     0     0     1     0
      row2     1     2     1     0     2
      row0     1     0     1     2     1
      row4     2     2     0     1     1
      

      pd.get_dummies

      pd.get_dummies(df['row']).T.dot(pd.get_dummies(df['col']))
      
            col0  col1  col2  col3  col4
      row0     1     2     0     1     1
      row2     1     0     2     1     2
      row3     0     1     0     2     0
      row4     0     1     2     2     1
      

      我如何通过只在两列上枢转来将数据帧从长转换为宽?

      第一步是给每一行分配一个数字--这个数字将是该值在枢轴结果中的行索引。这是使用groupby.cumcount完成的:

      df2.insert(0, 'count', df.groupby('A').cumcount())
      df2
      
         count  A   B
      0      0  a   0
      1      1  a  11
      2      2  a   2
      3      3  a  11
      4      0  b  10
      5      1  b  10
      6      2  b  14
      7      0  c   7
      

      第二步是使用新创建的列作为索引来调用dataframe.pivot

      df2.pivot(*df)
      # df.pivot(index='count', columns='A', values='B')
      
      A         a     b    c
      count                 
      0       0.0  10.0  7.0
      1      11.0  10.0  NaN
      2       2.0  14.0  NaN
      3      11.0   NaN  NaN
      

      pivot之后,如何将多索引扁平化为单索引

      如果columns使用字符串join键入object

      df.columns = df.columns.map('|'.join)
      

      其他格式

      df.columns = df.columns.map('{0[0]}|{0[1]}'.format) 
      

     类似资料:
    • 我开始使用Spark DataFrames,我需要能够枢轴的数据,以创建多个列1列多行。在Scalding中有内置的功能,我相信Python中的熊猫,但是我找不到任何新的Spark Dataframe。 我假设我可以编写某种自定义函数来实现这一点,但我甚至不知道如何开始,特别是因为我是Spark的新手。如果有人知道如何使用内置功能或如何在Scala中编写东西的建议来实现这一点,我们将不胜感激。

    • A 数据透视表介绍 B.1 什么是数据透视表? 数据透视表是一种可以快速汇总、分析大量数据表格的交互式工具。使用数据透视表可以按照数据表格的不同字段从多个角度进行透视,并建立交叉表格,用以查看数据表格不同层面的汇总信息、分析结果以及摘要数据。使用数据透视表可以深入分析数值数据,以帮助用户发现关键数据,并做出有关企业中关键数据的决策。 数据透视表是针对以下用途特别设计的:以友好的方式,查看大量的数据

    • 数据透视表显示二维交集的度量值,并在表格视图中表示数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 不透明度 设置背景颜色的不透明度。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水

    • 数据透视表显示二维交集的度量值,并在表格视图中表示数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水平对齐方式。 数据 字体 设置字段名

    • 数据透视表显示二维交集的度量值,并在表格视图中表示数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 不透明度 设置背景颜色的不透明度。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水