小编典典

如何旋转数据框?

all

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

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

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


设置

您可能会注意到,我显着地命名了我的列和相关列值,以对应于我将如何在下面的答案中进行旋转。

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

问题)

  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

  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

  10. 如何通过仅旋转两列将 DataFrame 从长转换为宽?鉴于,

    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
  1. 之后如何将多个索引展平为单个索引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

阅读 96

收藏
2022-03-11

共1个答案

小编典典

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

问题 1

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

发生这种情况是因为 pandas 试图重新索引具有重复条目的
acolumns或object。index可以使用多种方法来执行数据透视。其中一些不太适合当要求它在其中旋转的键存在重复时。例如。考虑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您希望在列索引中的级别。
    • pd.DataFrame.pivot_table

    • groupby具有更直观 API的美化版本。对于许多人来说,这是首选方法。并且是开发人员的预期方法。

    • 指定行级别、列级别、要聚合的值以及执行聚合的函数。
    • pd.DataFrame.set_index + pd.DataFrame.unstack

    • 对某些人来说方便直观(包括我自己)。无法处理重复的分组键。

    • groupby范例类似,我们指定最终将是行或列级别的所有列,并将它们设置为索引。然后unstack我们在列中显示我们想要的级别。如果剩余的索引级别或列级别不是唯一的,则此方法将失败。
    • pd.DataFrame.pivot

    • 非常相似set_index,因为它共享重复密钥限制。API 也非常有限。它只需要index, columns,的标量值values

    • pivot_table与我们选择要透视的行、列和值的方法类似。但是,我们无法聚合,如果行或列不是唯一的,则此方法将失败。
    • pd.crosstab

    • pivot_table是执行多项任务的最直观的方式,并且是最纯粹的形式。

    • pd.factorize + np.bincount

    • 这是一种非常先进的技术,非常晦涩,但速度非常快。它不能在所有情况下都使用,但是当它可以使用并且您使用它时,您将获得性能奖励。

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

问题 4

我能得到什么以外的东西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)
    

问题 5

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

请注意,forpivot_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')
    

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

  • pd.DataFrame.groupby

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

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

  • pd.DataFrame.groupby

      df.groupby(
      ['row', 'item', 'col']
    

    )[‘val0’].mean().unstack([‘item’, ‘col’]).fillna(0).sort_index(1)


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

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


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

  • 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


问题 10

如何通过仅旋转两列将 DataFrame 从长转换为宽?

第一步是为每一行分配一个数字——这个数字将是该值在透视结果中的行索引。这是使用
GroupBy.cumcount

      df2.insert(0, 'count', df2.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(*df2)
  # df2.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

DataFrame.pivot 只接受列,
DataFrame.pivot_table

也接受数组,因此GroupBy.cumcount可以直接作为 the 传递,index而无需创建显式列。

      df2.pivot_table(index=df2.groupby('A').cumcount(), columns='A', values='B')

  A         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

问题 11

之后如何将多个索引展平为单个索引pivot

如果columns输入object字符串join

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

别的format

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