Pandas pivot或groupby用于动态生成的列

时间:2015-10-06 09:10:51

标签: python pandas dataframe

我在超市中有一个包含销售信息的数据框。数据框中的每一行代表一个项目,具有多个特征作为列。原始的DataFrame是这样的:

In [1]: import pandas as pd
        my_data = [{'ticket_number' : '001', 'item' : 'tomato', 'ticket_price' : '21'},
               {'ticket_number' : '001', 'item' : 'candy', 'ticket_price' : '21'},
               {'ticket_number' : '001', 'item' : 'soup', 'ticket_price' : '21'},
               {'ticket_number' : '002', 'item' : 'soup', 'ticket_price' : '12'},
               {'ticket_number' : '002', 'item' : 'cola', 'ticket_price' : '12'},
               {'ticket_number' : '003', 'item' : 'beef', 'ticket_price' : '56'},
               {'ticket_number' : '003', 'item' : 'tomato', 'ticket_price' : '56'},
               {'ticket_number' : '003', 'item' : 'pork', 'ticket_price' : '56'}]
        df = pd.DataFrame(my_data)

In [2]: df
Out [2]:    
            ticket_number   ticket_price        item
         0        001            21           tomato
         1        001            21           candy
         2        001            21           soup
         3        002            12           soup
         4        002            12           cola
         5        003            56           beef
         6        003            56           tomato
         7        003            56           pork

我需要一个DataFrame,其中每一行代表一张票,其中包含所有购买的商品和票价作为列。在这个例子中:

            ticket_number   ticket_price      item1  item2  item3
         0        001            21           tomato candy  soup
         1        002            12           soup   cola
         2        003            56           beef   tomato pork

我尝试使用df.groupby(ticket_number).item.value_counts(),但这不会创建新列。我从未使用pivot_table,也许它很有用。

非常感谢任何帮助。

谢谢!

1 个答案:

答案 0 :(得分:4)

使用groupby制作列表的一种可能方法,然后可以将其转换为列:

In [24]: res = df.groupby(['ticket_number', 'ticket_price'])['item'].apply(list).apply(pd.Series)

In [25]: res
Out[25]:
                                 0       1     2
ticket_number ticket_price
001           21            tomato   candy  soup
002           12              soup    cola   NaN
003           56              beef  tomato  pork

然后,稍微清理一下这个结果:

In [27]: res.columns = ['item' + str(i + 1) for i in res.columns]

In [29]: res.reset_index()
Out[29]:
  ticket_number ticket_price   item1   item2 item3
0           001           21  tomato   candy  soup
1           002           12    soup    cola   NaN
2           003           56    beef  tomato  pork

另一种创建新列的方法,该列使用groupby.cumcount为每个组中的项目编号:

In [38]: df['item_number'] = df.groupby('ticket_number').cumcount()

In [39]: df
Out[39]:
     item ticket_number ticket_price  item_number
0  tomato           001           21            0
1   candy           001           21            1
2    soup           001           21            2
3    soup           002           12            0
4    cola           002           12            1
5    beef           003           56            0
6  tomato           003           56            1
7    pork           003           56            2

然后做一些重塑:

In [40]: df.set_index(['ticket_number', 'ticket_price', 'item_number']).unstack(-1)
Out[40]:
                              item
item_number                      0       1     2
ticket_number ticket_price
001           21            tomato   candy  soup
002           12              soup    cola   NaN
003           56              beef  tomato  pork

从这里开始,通过清理列名称,您可以实现与上述相同的功能。

set_indexuntack的重塑步骤也可以使用pivot_table完成:df.pivot_table(columns=['item_number'], index=['ticket_number', 'ticket _price'], values='item', aggfunc='first')