熊猫:将一对列转换为单元格

时间:2017-07-07 11:34:52

标签: python pandas

我有一个像这样的pandas数据框:

ts | thing_0 | qty_0 | thing_1 | qty_1 | thing_2 | qty_2
--------------------------------------------------------
1  | dog     |     5 | cat     |     3 | mouse   |     1
2  | house   |     6 | dog     |     4 | cat     |     2
...

我希望以thing成为列并且qty成为单元格值的方式对其进行转换。像这样:

ts | dog | cat | mouse | house
------------------------------
1  |   5 |   3 |     1 |     0
2  |   4 |   2 |     0 |     6
...

目前,我通过手动迭代df.values数组手动进行此转换,但这非常慢。使用pandas意味着有更快的方法实现吗?

我看过df.pivot,但无法找到描述thing_0qty_0之间关系的方法。

2 个答案:

答案 0 :(得分:4)

您可以使用lreshape来合并thingqty列:

In [10]: pd.lreshape(df, {'thing':['thing_0','thing_1','thing_2',], 'qty':['qty_0','qty_1','qty_2']})
Out[10]: 
   ts  thing  qty
0   1    dog    5
1   2  house    6
2   1    cat    3
3   2    dog    4
4   1  mouse    1
5   2    cat    2

然后pivot创建所需的DataFrame:

import pandas as pd

df = pd.DataFrame({'qty_0': [5, 6], 'qty_1': [3, 4], 'qty_2': [1, 2], 'thing_0': ['dog', 'house'], 'thing_1': ['cat', 'dog'], 'thing_2': ['mouse', 'cat'], 'ts': [1, 2]})

reshaped = pd.lreshape(df, {'thing':['thing_0','thing_1','thing_2',], 
                            'qty':['qty_0','qty_1','qty_2']})

result = reshaped.pivot(index='ts', columns='thing', values='qty')
print(result)

产量

thing  cat  dog  house  mouse
ts                           
1      3.0  5.0    0.0    1.0
2      2.0  4.0    6.0    0.0

我认为jezrael's solution更好,因为它利用了你希望合并的列名的规律性。 df.columns.str.split('_', expand=True)

更通用,重复性更低
{'thing':['thing_0','thing_1','thing_2',], 
 'qty':['qty_0','qty_1','qty_2']}

lreshape在您希望合并的列名称的情况下可能会有所帮助 是不规则的。

答案 1 :(得分:3)

您可以按str.split从列创建MultiIndex,然后按stackunstack重新塑造:

df = df.set_index('ts')
df.columns = df.columns.str.split('_', expand=True)
df = df.stack().reset_index(level=1, drop=True)
       .set_index('thing', append=True)['qty'].unstack(fill_value=0)
print (df)
thing  cat  dog  house  mouse
ts                           
1        3    5      0      1
2        2    4      6      0

使用pivot代替unstack的另一种解决方案:

df = df.set_index('ts')
df.columns = df.columns.str.split('_', expand=True)
df = df.stack().reset_index()
df = df.pivot(index='ts', columns='thing', values='qty').fillna(0).astype(int)
print (df)
thing  cat  dog  house  mouse
ts                           
1        3    5      0      1
2        2    4      6      0

第三个解决方案 - 为lreshape动态创建字典,然后使用unstack

注意 - 必须对列进行排序,如果不添加df = df.sort_index(axis=1)

t = [x for x in df.columns if x.startswith('thing')]
q = [x for x in df.columns if x.startswith('qty')]
df = pd.lreshape(df, {'thing':t, 'qty':q})
       .set_index(['ts','thing'])['qty'].unstack(fill_value=0)

print (df)
thing  cat  dog  house  mouse
ts                           
1        3    5      0      1
2        2    4      6      0

编辑:

lreshape现在没有记录,但将来可能会删除(with pd.wide_to_long too)。

可能的解决方案是将所有3个函数合并为一个 - 也许melt,但现在它没有实现。也许在一些新版本的熊猫中。然后我的答案会更新。