如何透视数据框

piR*_*red 296 python pivot group-by pandas pandas-groupby

  • 什么是枢轴?
  • 如何转动?
  • 这是一个支点吗?
  • 长格式到宽格式?

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

......但是我要试一试.


现有问题和答案的问题在于,问题通常集中在OP难以概括以便使用一些现有的良好答案的细微差别.但是,没有一个答案试图给出全面的解释(因为这是一项艰巨的任务)

从我的谷歌搜索中查看一些示例

  1. 如何在Pandas中透视数据框?
    • 好问答.但答案只回答了具体问题,几乎没有解释.
  2. pandas将表转移到数据框
    • 在这个问题中,OP关注的是枢轴的输出.即列的外观.OP希望它看起来像R.这对熊猫用户来说并不是很有帮助.
  3. 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
Run Code Online (Sandbox Code Playgroud)

问题(S)

  1. 我为什么得到 ValueError: Index contains duplicate entries, cannot reshape

  2. 如何进行数据透视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
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如何进行数据透视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
    
    Run Code Online (Sandbox Code Playgroud)
  4. 我可以得到比其他的东西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
    
    Run Code Online (Sandbox Code Playgroud)
  5. 我可以一次做多个聚合吗?

           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
    
    Run Code Online (Sandbox Code Playgroud)
  6. 我可以聚合多个值列吗?

          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
    
    Run Code Online (Sandbox Code Playgroud)
  7. 可以按多列细分吗?

    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
    
    Run Code Online (Sandbox Code Playgroud)
  8. 要么

    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
    
    Run Code Online (Sandbox Code Playgroud)
  9. 我可以汇总列和行一起出现的频率,也就是"交叉制表"吗?

    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
    
    Run Code Online (Sandbox Code Playgroud)

piR*_*red 256

我们首先回答第一个问题:

问题1

我为什么得到 ValueError: Index contains duplicate entries, cannot reshape

发生这种情况是因为pandas正在尝试重新索引具有重复条目的对象columnsindex对象.可以使用不同的方法来执行枢轴.它们中的一些不适合于当要求其转动的键的重复时.例如.考虑pd.DataFrame.pivot.我知道有重复的条目共享rowcol值:

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

True
Run Code Online (Sandbox Code Playgroud)

所以当我pivot使用时

df.pivot(index='row', columns='col', values='val0')
Run Code Online (Sandbox Code Playgroud)

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

df.set_index(['row', 'col'])['val0'].unstack()
Run Code Online (Sandbox Code Playgroud)

这是我们可以用来转动的习语列表

  1. pd.DataFrame.groupby + pd.DataFrame.unstack
    • 做任何类型的枢轴的良好通用方法
    • 您可以指定将构成一个组中的透视行级别和列级别的所有列.您可以通过选择要聚合的剩余列以及要执行聚合的功能来执行此操作.最后,您unstack想要在列索引中的级别.
  2. pd.DataFrame.pivot_table
    • groupby具有更直观API的美化版本.对于许多人来说,这是首选方法.并且是开发人员的预期方法.
    • 指定行级别,列级别,要聚合的值以及执行聚合的函数.
  3. pd.DataFrame.set_index + pd.DataFrame.unstack
    • 一些方便直观(包括我自己).无法处理重复的分组键.
    • groupby范例类似,我们指定最终将是行级别或列级别的所有列,并将这些列设置为索引.然后unstack我们在列中想要的级别.如果其余索引级别或列级别不唯一,则此方法将失败.
  4. pd.DataFrame.pivot
    • 非常类似于set_index它共享重复键限制.API也非常有限.只需要对标量值index,columns,values.
    • pivot_table我们选择要转动的行,列和值的方法类似.但是,我们无法聚合,如果行或列不唯一,则此方法将失败.
  5. pd.crosstab
    • 这是一个专门的版本,pivot_table并以其最纯粹的形式是执行多个任务的最直观的方式.
  6. pd.factorize + np.bincount
    • 这是一种非常先进但非常快速的非常先进的技术.它不能在所有情况下使用,但是当它可以使用并且您习惯使用它时,您将获得性能奖励.
  7. pd.get_dummies + pd.DataFrame.dot
    • 我用它来巧妙地执行交叉制表.

例子

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

问题3

如何进行数据透视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
      
      Run Code Online (Sandbox Code Playgroud)
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].mean().unstack(fill_value=0)
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.crosstab

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

问题4

我可以得到比其他的东西mean,如可能sum


问题5

我可以一次做多个聚合吗?

请注意,我pivot_tablecross_tab我需要传递callables列表.另一方面,groupby.agg能够为有限数量的特殊功能采用字符串. groupby.agg也可以采用我们传递给其他人的相同的callables,但是利用字符串函数名称通常更有效,因为可以获得效率.

  • 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
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].agg(['size', 'mean']).unstack(fill_value=0)
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.crosstab

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

问题6

我可以聚合多个值列吗?

  • 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
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0', 'val1'].mean().unstack(fill_value=0)
    
    Run Code Online (Sandbox Code Playgroud)

问题7

可以按多列细分吗?

  • 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
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.DataFrame.groupby

    df.groupby(
        ['row', 'item', 'col']
    )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
    
    Run Code Online (Sandbox Code Playgroud)

问题8

可以按多列细分吗?

  • 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
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.DataFrame.groupby

    df.groupby(
        ['key', 'row', 'item', 'col']
    )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.DataFrame.set_index 因为这组键对于行和列都是唯一的

    df.set_index(
        ['key', 'row', 'item', 'col']
    )['val0'].unstack(['item', 'col']).fillna(0).sort_index(1)
    
    Run Code Online (Sandbox Code Playgroud)

问题9

我可以汇总列和行一起出现的频率,也就是"交叉制表"吗?

  • 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
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].size().unstack(fill_value=0)
    
    Run Code Online (Sandbox Code Playgroud)
  • pd.cross_tab

    pd.crosstab(df['row'], df['col'])
    
    Run Code Online (Sandbox Code Playgroud)
  • 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
    
    Run Code Online (Sandbox Code Playgroud)
  • 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
    
    Run Code Online (Sandbox Code Playgroud)

  • 您能否考虑扩展[官方文档](https://pandas.pydata.org/pandas-docs/stable/reshaping.html)? (37认同)
  • 问题10中的列不需要插入,可以直接作为数据透视表中的参数传递 (2认同)
  • `pivot_table()` 和 `crosstab()` 现在可以采用字符串函数名称,尽管我不确定它何时更改,因为它没有非常清楚地记录。我正在使用 Pandas 1.4.4。 (2认同)

Myk*_*tko 16

为了更好地理解函数透视的工作原理,您可以查看Pandas 文档中的示例。但是,pivot如果您有重复的索引列 ( foo- bar) 组合(如df第二个示例中所示),则会失败:

枢

pivot函数相反, pivot_tablemean默认支持使用该函数进行数据聚合。这是聚合函数的示例sum

数据透视表


Ch3*_*teR 13

扩展@piRSquared 的回答问题 10 的另一个版本

问题 10.1

数据框:

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
Run Code Online (Sandbox Code Playgroud)

输出:

   0     1     2
A
1  a     b     c
2  a     b  None
3  a  None  None
5  c  None  None
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

或者使用pd.pivot_tablewith更好的选择df.squeeze.

t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
out = pd.DataFrame(t.tolist(),index=t.index)
Run Code Online (Sandbox Code Playgroud)


cot*_*ail 7

呼叫reset_index()(连同add_suffix()

通常,在您致电或reset_index()后需要。例如,进行以下转换(其中一列成为列名称)pivot_tablepivot

资源

您使用以下代码,其中之后pivot,为新创建的列名称添加前缀,并将索引(在本例中"movies")转换回列并删除轴名称的名称:

df.pivot(index='movie', columns='week', values='sales').add_prefix('week_').reset_index().rename_axis(columns=None)
Run Code Online (Sandbox Code Playgroud)

正如其他答案提到的,“枢轴”可能指两种不同的操作:

  1. 非堆叠聚合(即使结果groupby.agg更宽。)
  2. 重塑(类似于 Excel、reshapenumpy 或pivot_widerR 中的透视)

1. 聚合

pivot_table或者crosstab只是未堆叠的groupby.agg操作结果。事实上,源代码表明,在幕后,以下内容是正确的:

  • pivot_table= groupby+ unstack阅读此处了解更多信息。)
  • crosstab=pivot_table

注意:您可以使用列名称列表作为index,columnsvalues参数。

df.groupby(rows+cols)[vals].agg(aggfuncs).unstack(cols)
# equivalently,
df.pivot_table(vals, rows, cols, aggfuncs)
Run Code Online (Sandbox Code Playgroud)
1.1. crosstab是 的一个特例pivot_table;因此groupby+unstack

以下是等效的:

  • pd.crosstab(df['colA'], df['colB'])
  • df.pivot_table(index='colA', columns='colB', aggfunc='size', fill_value=0)
  • df.groupby(['colA', 'colB']).size().unstack(fill_value=0)

请注意, 的pd.crosstab开销要大得多,因此它比pivot_tablegroupby+慢得多unstack。事实上,正如此处所述,也比+pivot_table慢。groupbyunstack

2. 重塑

pivot是一个更有限的版本pivot_table,其目的是将长数据帧重塑为长数据帧。

df.set_index(rows+cols)[vals].unstack(cols)
# equivalently, 
df.pivot(index=rows, columns=cols, values=vals)
Run Code Online (Sandbox Code Playgroud)
2.1. 如问题 10 所示增加行/列

您还可以将问题 10 中的见解应用到多列透视操作。有两种情况:

  • “long-to-long”:通过增加索引来重塑

    情况1

    代码:

    df = pd.DataFrame({'A': [1, 1, 1, 2, 2, 2], 'B': [*'xxyyzz'], 
                       'C': [*'CCDCDD'], 'E': [100, 200, 300, 400, 500, 600]})
    rows, cols, vals = ['A', 'B'], ['C'], 'E'
    
    # using pivot syntax
    df1 = (
        df.assign(ix=df.groupby(rows+cols).cumcount())
        .pivot(index=[*rows, 'ix'], columns=cols, values=vals)
        .fillna(0, downcast='infer')
        .droplevel(-1).reset_index().rename_axis(columns=None)
    )
    
    # equivalently, using set_index + unstack syntax
    df1 = (
        df
        .set_index([*rows, df.groupby(rows+cols).cumcount(), *cols])[vals]
        .unstack(fill_value=0)
        .droplevel(-1).reset_index().rename_axis(columns=None)
    )
    
    Run Code Online (Sandbox Code Playgroud)
  • “long-to-wide”:通过增加列来重塑

    案例2

    代码:

    df1 = (
        df.assign(ix=df.groupby(rows+cols).cumcount())
        .pivot(index=rows, columns=[*cols, 'ix'])[vals]
        .fillna(0, downcast='infer')
    )
    df1 = df1.set_axis([f"{c[0]}_{c[1]}" for c in df1], axis=1).reset_index()
    
    # equivalently, using the set_index + unstack syntax
    df1 = (
        df
        .set_index([*rows, df.groupby(rows+cols).cumcount(), *cols])[vals]
        .unstack([-1, *range(-2, -len(cols)-2, -1)], fill_value=0)
    )
    df1 = df1.set_axis([f"{c[0]}_{c[1]}" for c in df1], axis=1).reset_index()
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用set_index+unstack语法的最小情况:

    案例3

    代码:

    df1 = df.set_index(['A', df.groupby('A').cumcount()])['E'].unstack(fill_value=0).add_prefix('Col').reset_index()
    
    Run Code Online (Sandbox Code Playgroud)

1 pivot_table()聚合值并将其拆散。具体来说,它从索引和列中创建一个平面列表,groupby()将此列表作为分组器调用,并使用传递的聚合器方法进行聚合(默认为mean)。然后在聚合之后,它unstack()通过列列表进行调用。所以在内部,pivot_table = groupby + unstack。此外,如果fill_value通过,fillna()则调用。

也就是说,生成的方法和下面例子中的pv_1生成方法是一样的。gb_1

pv_1 = df.pivot_table(index=rows, columns=cols, values=vals, aggfunc=aggfuncs, fill_value=0)
# internal operation of `pivot_table()`
gb_1 = df.groupby(rows+cols)[vals].agg(aggfuncs).unstack(cols).fillna(0, downcast="infer")
pv_1.equals(gb_1) # True
Run Code Online (Sandbox Code Playgroud)

2 crosstab()次调用pivot_table(),即crosstab = hub_table。具体来说,它根据传递的值数组构建一个 DataFrame,通过公共索引对其进行过滤并调用pivot_table(). 它的限制更大,pivot_table()因为它只允许类似一维数组的 as values,而不像pivot_table()可以有多个列的 as values