python pandas groupby多列到一行

时间:2015-02-09 23:07:11

标签: python pandas dataframe

我想在密钥上对数据帧进行分组,在这种情况下是clientid。并将每个键的所有列连接成每个键的一个长行。

e.g。

clientid, name, age, company
1,        tom,  31,  awesome
1,        jen,  26,  argos
2,        bob,  18,  hmv
3,        ted,  12,  mcdonalds
4,        sarah,30,  MnS
4,        mike, 52,  Mns
4,        luke, 75,  argos

想要的结果

clientid, name, age, company,  name, age, company, name, age, company
1,        tom,  31,  awesome,  jen,  26,  argos,
2,        bob,  18,  hmv,
3,        ted,  12,  mcdonadls,
4,        sarah,30,  MnS,      mike, 52,  MnS,     luke, 75,  argos,

给出了类似的问题和解决方案

df_info = df1.groupby('clientid')['info'].unique().apply(pd.Series).reset_index()
info_len = len([col for col in df_info if str(col).isdigit()])
df_info.columns = ['clientid'] + ['info'] * info_len
df_info

但我无法找到如何将其应用于多列

2 个答案:

答案 0 :(得分:0)

这带有一个健康警告,因为你失去了大熊猫的力量,让结构允许你分组,优秀的性能,强大而干净的语法(所以在某种意义上它是你的特色)不能轻易做到这一点!)......而且它不是很难吃。

所以我强烈建议不要这样做,因为几乎可以肯定有更好的方法去做你正在做的事......


我认为你需要将clientid分组,然后提取这些字符串......

In [11]: df1 = df.set_index('clientid')

In [12]: df1
Out[12]:
           name  age    company
clientid
1           tom   31    awesome
1           jen   26      argos
2           bob   18        hmv
3           ted   12  mcdonalds
4         sarah   30        MnS
4          mike   52        Mns
4          luke   75      argos

In [13]: g = df1.groupby(df1.index)

我可能会考虑在每个群组中使用to_csv

In [14]: g.apply(lambda x: x.to_csv(header=False, index=False, line_terminator=','))
Out[14]:
clientid
1                      tom,31,awesome,jen,26,argos,
2                                       bob,18,hmv,
3                                 ted,12,mcdonalds,
4           sarah,30,MnS,mike,52,Mns,luke,75,argos,
dtype: object

另一种方法是申请:

In [15]: g.apply(lambda x: pd.concat([row for _, row in x.iterrows()]).values)
Out[15]:
clientid
1                         [tom, 31, awesome, jen, 26, argos]
2                                             [bob, 18, hmv]
3                                       [ted, 12, mcdonalds]
4           [sarah, 30, MnS, mike, 52, Mns, luke, 75, argos]
dtype: object

你必须稍微破解一下以获得正确的标题:

In [16]: list(df1.columns) * g.apply(len).max()
Out[16]: ['name', 'age', 'company', 'name', 'age', 'company', 'name', 'age', 'company']

因此,您可以执行以下操作:

In [21]: s = g.apply(lambda x: pd.concat([row for _, row in x.iterrows()]).values).apply(lambda row: ','.join([str(x) for x in row]))

In [22]: s.name = ','.join(list(df1.columns) * g.apply(len).max())

In [23]: s.to_frame().to_csv(quotechar=" ")  # Note: this is a hack since quoting=0 seems to be ignored
Out[23]: 'clientid, name,age,company,name,age,company,name,age,company \n1, tom,31,awesome,jen,26,argos \n2, bob,18,hmv \n3, ted,12,mcdonalds \n4, sarah,30,MnS,mike,52,Mns,luke,75,argos \n'

答案 1 :(得分:0)

我尝试了几种方法,并提出了一些改进版的安迪,我发现它很有效。

grouped = df1.groupby('clientid')
flattenedSeries = grouped.apply(lambda x: x.to_csv(header=False, index=False, line_terminator=','))
flattenedSeries = pd.DataFrame(flattenedSeries, columns=['data'])
ready = flattenedSeries['data'].apply(lambda x: pd.Series(x.split(',')))

创建新的列标题

newcolumns = list(df1.columns) * grouped.apply(len).max()

添加神秘列以匹配pd.Series中创建的空白(x.split(','))

newcolumns = newcolumns + ['extra']
ready.columns = newcolumns

为索引提供一个类型以帮助将来合并

ready.index= ready.index.astype('int64')

如果在任何列数据中使用了行终止符,则可以更改行终止符。