我见过很多关于数据透视表的问题。即使他们不知道他们在询问数据透视表,他们通常也是如此。几乎不可能编写一个包含旋转所有方面的规范问题和答案......
......但我要试一试。
您可能会注意到,我显着地命名了我的列和相关列值,以对应于我将如何在下面的答案中进行旋转。
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
为什么我会得到ValueError: Index contains duplicate entries, cannot reshape
ValueError: Index contains duplicate entries, cannot reshape
如何旋转df以使col值是列,row值是索引,平均值val0是值?
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?
0
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吗?
mean
sum
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
要么
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
我可以汇总列和行一起出现的频率,也就是“交叉表”吗?
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
如何通过仅旋转两列将 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
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
我们从回答第一个问题开始:
发生这种情况是因为 pandas 试图重新索引具有重复条目的 acolumns或object。index可以使用多种方法来执行数据透视。其中一些不太适合当要求它在其中旋转的键存在重复时。例如。考虑pd.DataFrame.pivot。我知道有重复的条目共享row和col值:
columns
index
pd.DataFrame.pivot
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
pd.DataFrame.groupby
pd.DataFrame.unstack
unstack
pd.DataFrame.pivot_table
groupby具有更直观 API的美化版本。对于许多人来说,这是首选方法。并且是开发人员的预期方法。
groupby
pd.DataFrame.set_index + pd.DataFrame.unstack
pd.DataFrame.set_index
对某些人来说方便直观(包括我自己)。无法处理重复的分组键。
非常相似set_index,因为它共享重复密钥限制。API 也非常有限。它只需要index, columns,的标量值values。
set_index
values
pivot_table
pd.crosstab
这pivot_table是执行多项任务的最直观的方式,并且是最纯粹的形式。
pd.factorize + np.bincount
pd.factorize
np.bincount
这是一种非常先进的技术,非常晦涩,但速度非常快。它不能在所有情况下都使用,但是当它可以使用并且您使用它时,您将获得性能奖励。
pd.get_dummies + pd.DataFrame.dot
pd.get_dummies
pd.DataFrame.dot
我用它来巧妙地执行交叉制表。
我将为每个后续答案和问题做的是使用 pd.DataFrame.pivot_table. 然后,我将提供执行相同任务的替代方案。
fill_value默认情况下未设置。我倾向于适当地设置它。在这种情况下,我将其设置为0. 请注意,我跳过了 问题 2 ,因为它与此答案相同,但没有fill_value
fill_value
aggfunc='mean'是默认值,我不必设置它。我包括它是明确的。
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
df.groupby(['row', 'col'])['val0'].mean().unstack(fill_value=0)
pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc='mean').fillna(0)
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
df.groupby(['row', 'col'])['val0'].sum().unstack(fill_value=0)
pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc='sum').fillna(0)
请注意,forpivot_table和crosstab我需要传递可调用列表。另一方面,groupby.agg能够为有限数量的特殊功能获取字符串。 groupby.agg也会采用我们传递给其他人的相同可调用对象,但利用字符串函数名称通常更有效,因为可以提高效率。
crosstab
groupby.agg
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
df.groupby(['row', 'col'])['val0'].agg(['size', 'mean']).unstack(fill_value=0)
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']了,但我们本可以完全放弃
values=['val0', 'val1']
df.pivot_table( values=['val0', 'val1'], index='row', columns='col', fill_value=0, aggfunc='mean') val0 val1
df.groupby(['row', 'col'])['val0', 'val1'].mean().unstack(fill_value=0)
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
df.groupby( ['row', 'item', 'col']
)[‘val0’].mean().unstack([‘item’, ‘col’]).fillna(0).sort_index(1)
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
df.groupby( ['key', 'row', 'item', 'col']
pd.DataFrame.set_index 因为键集对于行和列都是唯一的
df.set_index( ['key', 'row', 'item', 'col']
)[‘val0’].unstack([‘item’, ‘col’]).fillna(0).sort_index(1)
df.pivot_table(index='row', columns='col', fill_value=0, aggfunc='size') col col0 col1 col2 col3 col4
df.groupby(['row', 'col'])['val0'].size().unstack(fill_value=0)
pd.crosstab(df['row'], df['col'])
# 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)
'row'
j
c
'col'
n
m
i * m + j
n * m
(n, m)
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(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
如何通过仅旋转两列将 DataFrame 从长转换为宽?
DataFrame.pivot
第一步是为每一行分配一个数字——这个数字将是该值在透视结果中的行索引。这是使用 GroupBy.cumcount :
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_table
而 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
之后如何将多个索引展平为单个索引pivot
如果columns输入object字符串join
object
join
df.columns = df.columns.map('|'.join)
别的format
format
df.columns = df.columns.map('{0[0]}|{0[1]}'.format)