如何转动数据框

时间:2017-11-07 08:00:28

标签: python pandas group-by pivot pandas-groupby

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

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

......但我要试一试。

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

从我的google search

中查看一些示例
  1. How to pivot a dataframe in Pandas?
    • 很好的问答。但答案只回答了具体问题而几乎没有解释。
  2. pandas pivot table to data frame
    • 在这个问题中,OP关注枢轴的输出。即列的外观。 OP希望它看起来像R.这对大熊猫用户来说不是很有帮助。
  3. pandas pivoting a dataframe, duplicate rows
    • 另一个不错的问题,但答案集中在一种方法,即pd.DataFrame.pivot
  4. 因此,每当有人搜索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
    

    问题(S)

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

    2. 如何透视df以使col值为列,row值为索引,val0的平均值为?< / p>

      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
      
    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
      
    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
      
    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
      
    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
      
    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
      
    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
      
    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
      

4 个答案:

答案 0 :(得分:209)

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

问题1

  

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

这是因为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()

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

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

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

    问题3

      

    如何透过df以使col值为列,row值为索引,val0的平均值为值,缺失值为{ {1}}?

    • 0

        默认情况下未设置
      • pd.DataFrame.pivot_table。我倾向于适当地设置它。在这种情况下,我将其设置为fill_value。请注意,我跳过问题2 ,因为它与没有0
      • 的答案相同
      • 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

    问题4

      

    我可以获得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

    问题5

      

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

    请注意,对于pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc='sum').fillna(0) pivot_table,我需要传递callables列表。另一方面,cross_tab能够为有限数量的特殊函数获取字符串。 groupby.agg也会采用我们传递给其他人的相同的callables,但是利用字符串函数名称通常会更有效率,因为可以获得效率。

    • 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

    问题6

      

    我可以汇总多个值列吗?

    • 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

    问题7

      

    可以按多列细分吗?

    • 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

    问题8

      

    可以按多列细分吗?

    • 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

    问题9

      

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

    • 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.cross_tab
    • 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

答案 1 :(得分:7)

扩展@piRSquared's answer Question 10

的另一个版本

问题10.1

DataFrame:

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.squeeze.

结合使用会更好
t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
out = pd.DataFrame(t.tolist(),index=t.index)

答案 2 :(得分:3)

为了更好地理解 pivot 的工作原理,您可以查看 Pandas 文档中的 example

enter image description here

df = pd.DataFrame({
    'foo': ['one', 'one', 'one', 'two', 'two', 'two'],
    'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
    'baz': [1, 2, 3, 4, 5, 6],
    'zoo': ['x', 'y', 'z', 'q', 'w', 't']
})

输入表:

   foo bar  baz zoo
0  one   A    1   x
1  one   B    2   y
2  one   C    3   z
3  two   A    4   q
4  two   B    5   w
5  two   C    6   t

枢轴

pd.pivot(
    data=df,        
    index='foo',    # Column to use to make new frame’s index. If None, uses existing index.
    columns='bar',  # Column to use to make new frame’s columns.
    values='baz'    # Column(s) to use for populating new frame’s values.
)

输出表:

bar  A  B  C
foo         
one  1  2  3
two  4  5  6

答案 3 :(得分:-1)

 def to_explode(ttype,df, by):
    # Filter dtypes and split into column names and type description
    cols, dtypes = zip(*((c, t) for (c, t) in df.dtypes if c not in by))
    # Create and explode an array of (column_name, column_value) structs
    kvs = explode(array([
      struct(lit(c).alias(ttype+"Period"), col(c).alias(ttype+"Value"))
          for c in cols])).alias("kvs")
    # print(kvs)
    return df.select(by + [kvs]).select(by +
                    ["kvs."+ttype+"Period", "kvs."+ttype+"Value"])