Pandas 按两列分组并展开第三列

mir*_*rix 8 python pandas

我有一个具有以下结构的 Pandas 数据框:

A       B       C
a       b       1
a       b       2
a       b       3
c       d       7
c       d       8
c       d       5
c       d       6
c       d       3
e       b       4
e       b       3
e       b       2
e       b       1
Run Code Online (Sandbox Code Playgroud)

我想把它改成这样:

A       B       C1      C2      C3      C4      C5
a       b       1       2       3       NAN     NAN
c       d       7       8       5       6       3
e       b       4       3       2       1       NAN
Run Code Online (Sandbox Code Playgroud)

换句话说,类似于对 A 和 B 进行分组并将 C 扩展到不同的列。

知道每组的长度是不同的。

C已经订购了

较短的组可以有 NAN 或 NULL 值(空),这并不重要。

jez*_*ael 12

使用GroupBy.cumcountand 和pandas.Series.add1, 从 1 开始命名新列,然后将其传递给DataFrame.pivot, 并添加DataFrame.add_prefix以重命名列(C1、C2、C3 等...)。最后用于DataFrame.rename_axis删除索引原始名称('g')并MultiIndex使用DataFrame.reset_indexcolumns将其转换为列A,B

df['g'] = df.groupby(['A','B']).cumcount().add(1)

df = df.pivot(['A','B'], 'g', 'C').add_prefix('C').rename_axis(columns=None).reset_index()
print (df)
   A  B   C1   C2   C3   C4   C5
0  a  b  1.0  2.0  3.0  NaN  NaN
1  c  d  7.0  8.0  5.0  6.0  3.0
2  e  b  4.0  3.0  2.0  1.0  NaN
Run Code Online (Sandbox Code Playgroud)

因为NaN默认情况下是 float 类型,如果您需要列 dtype 为整数,请DataFrame.astype添加Int64

df['g'] = df.groupby(['A','B']).cumcount().add(1)

df = (df.pivot(['A','B'], 'g', 'C')
        .add_prefix('C')
        .astype('Int64')
        .rename_axis(columns=None)
        .reset_index())
print (df)
   A  B  C1  C2  C3    C4    C5
0  a  b   1   2   3  <NA>  <NA>
1  c  d   7   8   5     6     3
2  e  b   4   3   2     1  <NA>
Run Code Online (Sandbox Code Playgroud)

编辑:如果要添加的新列数量达到上限N,则意味着它们A,B是重复的。因此,需要添加g1, g2具有整数和模除法的辅助组,在索引中添加一个新级别:

N = 4
g  = df.groupby(['A','B']).cumcount()
df['g1'], df['g2'] = g // N, (g % N) + 1
df = (df.pivot(['A','B','g1'], 'g2', 'C')
        .add_prefix('C')
        .droplevel(-1)
        .rename_axis(columns=None)
        .reset_index())
print (df)
   A  B   C1   C2   C3   C4
0  a  b  1.0  2.0  3.0  NaN
1  c  d  7.0  8.0  5.0  6.0
2  c  d  3.0  NaN  NaN  NaN
3  e  b  4.0  3.0  2.0  1.0 
Run Code Online (Sandbox Code Playgroud)