如何在某些条件下对pandas数据帧进行分组

时间:2016-02-20 17:20:32

标签: python pandas

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

colspan=2

上面的数据框中有很多行。我想要实现的是,是否引入新菜肴驱使我的用户回来。 buyer_id item_id order_id date 139 57 387 2015-12-28 140 9 388 2015-12-28 140 57 389 2015-12-28 36 9 390 2015-12-28 64 49 404 2015-12-29 146 49 405 2015-12-29 81 49 406 2015-12-29 140 80 407 2015-12-30 139 81 408 2015-12-30 映射到菜名。我想看到的是,如果特定用户在不同的日子订购不同的菜肴。 例如item_id 然后我想将此用户标记为buyer_id 140 has ordered two dishes item_id (9,57) on 28th Dec and same buyer has ordered different dish (item_id = 80) on 30th Dec

我是如何在python中这样做的

1

它为我提供了以下输出

item_wise_order.groupby(['date','buyer_id'])['item_id'].apply(lambda x:    
x.tolist())

期望的输出

date        buyer_id
2015-12-28  139                 [57]
            140                 [9,57]     
            36                  [9]
2015-12-29  64                  [49]
            146                 [49]
            81                  [49]
2015-12-30  140                 [80]
            139                 [81]

2 个答案:

答案 0 :(得分:2)

与Anton的答案类似,但使用了应用

users = df.groupby('buyer_id').apply(lambda r: r['item_id'].unique().shape[0] > 1 and 
                                               r['date'].unique().shape[0] > 1 )*1
df.set_index('buyer_id', inplace=True)
df['good_user'] = users

结果:

          item_id  order_id        date  good_user
buyer_id
139            57       387  2015-12-28          1
140             9       388  2015-12-28          1
140            57       389  2015-12-28          1
36              9       390  2015-12-28          0
64             49       404  2015-12-29          0
146            49       405  2015-12-29          0
81             49       406  2015-12-29          0
140            80       407  2015-12-30          1
139            81       408  2015-12-30          1

编辑因为我想到了另一种情况:假设数据显示买家在两天内购买了相同的两件(或更多件)商品。此用户是否应标记为1或0?因为有效,他/她实际上并没有在第二次约会时选择任何不同的东西。 因此,请在下表中选择买方81。你看他们两个日期只买49和50。

    buyer_id   item_id order_id    date
         139        57      387    2015-12-28
         140         9      388    2015-12-28
         140        57      389    2015-12-28
          36         9      390    2015-12-28
          64        49      404    2015-12-29
         146        49      405    2015-12-29
          81        49      406    2015-12-29
         140        80      407    2015-12-30
         139        81      408    2015-12-30
          81        50      406    2015-12-29
          81        49      999    2015-12-30
          81        50      999    2015-12-30

为了适应这一点,这就是我提出的问题(有点难看但应该工作)

# this function is applied to all buyers
def find_good_buyers(buyer):
    # which dates the buyer has made a purchase
    buyer_dates = buyer.groupby('date')
    # a string representing the unique items purchased at each date
    items_on_date = buyer_dates.agg({'item_id': lambda x: '-'.join(x.unique())})
    # if there is more than 1 combination of item_id, then it means that
    # the buyer has purchased different things in different dates
    # so this buyer must be flagged to 1
    good_buyer = (len(items_on_date.groupby('item_id').groups) > 1) * 1
    return good_buyer


df['item_id'] = df['item_id'].astype('S')
buyers = df.groupby('buyer_id') 

good_buyer = buyers.apply(find_good_buyers)
df.set_index('buyer_id', inplace=True)
df['good_buyer'] = good_buyer
df.reset_index(inplace=True)

这适用于买方81将其设置为0,因为一旦按日期分组,购买的两个日期将具有相同的“49-50”购买项目组合,因此组合数量= 1和买家将被标记为0。

答案 1 :(得分:1)

您可以按buyer_id分组,然后使用np.unique汇总列。然后,对于有多个日期和item_ids的行,您将获得np.ndarrays。您可以找到isinstance np.ndarray的行,您将获得bool系列,您可以将其传递到聚合数据框并找到感兴趣的买家。通过使用获得的buyers过滤原始数据框,您可以使用flag填充loc的行:

df_agg = df.groupby('buyer_id')[['date', 'item_id']].agg(np.unique)
df_agg = df_agg.applymap(lambda x: isinstance(x, np.ndarray))

buyers = df_agg[(df_agg['date']) & (df_agg['item_id'])].index
mask = df['buyer_id'].isin(buyers)

df['flag'] = 0
df.loc[mask, 'flag'] = 1

In [124]: df
Out[124]: 
   buyer_id  item_id  order_id        date  flag
0       139       57       387  2015-12-28     1
1       140        9       388  2015-12-28     1
2       140       57       389  2015-12-28     1
3        36        9       390  2015-12-28     0
4        64       49       404  2015-12-29     0
5       146       49       405  2015-12-29     0
6        81       49       406  2015-12-29     0
7       140       80       407  2015-12-30     1
8       139       81       408  2015-12-30     1

第一步和第二步的输出:

In [146]: df.groupby('buyer_id')[['date', 'item_id']].agg(np.unique)
Out[146]: 
                              date      item_id
buyer_id                                       
36                      2015-12-28            9
64                      2015-12-29           49
81                      2015-12-29           49
139       [2015-12-28, 2015-12-30]     [57, 81]
140       [2015-12-28, 2015-12-30]  [9, 57, 80]
146                     2015-12-29           49

In [148]: df_agg.applymap(lambda x: isinstance(x, np.ndarray))
Out[148]: 
           date item_id
buyer_id               
36        False   False
64        False   False
81        False   False
139        True    True
140        True    True
146       False   False