pandas:在组内进行计算的有效方法

时间:2013-05-17 13:32:32

标签: group-by pandas resampling

我正在使用这样的交易数据:

Purchase data        | Buyer | Product | Quantity
--------------------------------------------------
2013-01-01 13:00:00  | Carl  | A       | 5
2013-01-01 13:05:00  | Mark  | B       | 2
2013-01-01 20:00:00  | Carl  | A       | 5
2013-01-02 10:00:00  | Joe   | A       | 10
2013-01-02 14:00:00  | Carl  | A       | 5

现在,我想根据购买日期,买方和产品进行分组,以计算以下问题:

  • 客户每天在部门工作多长时间(首次购买时间 - 上次购买时间)?如果只让我们假设1小时。

  • 直到中午和午夜之前,哪些是最畅销的产品?

  • 如何在不使用平均值但使用自定义函数的情况下计算群组间统计数据(例如平均购买数量)?

更新

  • 是否有可能迭代组内的列,例如我想计算一个列,显示Carl和所有其他买家之间的数量差异。 它看起来像这样

    Date       | Buyer | Difference
    -------------------------------
    2013-01-01 | Carl  | 0
    2013-01-01 | Mark  | -3
    2013-01-01 | Carl  | 0
    2013-01-01 | Joe   | 5
    
  • 此外,还有没有购买的日子?

我非常感谢你的帮助,谢谢

安迪

1 个答案:

答案 0 :(得分:2)

鉴于此设置:

import pandas as pd
import datetime as DT
df = pd.DataFrame({
    'Buyer': 'Carl Mark Carl Joe Joe Carl'.split(),
    'Product': list('ABAABA'),
    'Quantity': [5,2,5,10,1,5]
    }, index=[
        DT.datetime(2013,1,1,13,0),
        DT.datetime(2013,1,1,13,5),
        DT.datetime(2013,1,1,20,0),
        DT.datetime(2013,1,2,10,0),
        DT.datetime(2013,1,2,12,0),                                      
        DT.datetime(2013,1,2,14,0),
        ])

print(df)
#                     Buyer Product  Quantity
# 2013-01-01 13:00:00  Carl       A         5
# 2013-01-01 13:05:00  Mark       B         2
# 2013-01-01 20:00:00  Carl       A         5
# 2013-01-02 10:00:00   Joe       A        10
# 2013-01-02 12:00:00   Joe       B         1
# 2013-01-02 14:00:00  Carl       A         5

客户每天在部门工作多长时间(首次购买时间 - 上次购买时间)?如果只让我们假设1小时。

def lingertime(df):
    dates = df.index.map(lambda d: d.date())
    def linger(grp):
        dates = grp.index
        x = (dates.max()-dates.min())
        return x or DT.timedelta(hours=1)
    return df.groupby([dates, 'Buyer']).apply(linger)

print(lingertime(df))
# date        Buyer
# 2013-01-01  Carl     7:00:00
#             Mark     1:00:00
# 2013-01-02  Carl     1:00:00
#             Joe      2:00:00

直到中午和午夜之前哪些是畅销产品?

def product_quantity(df, from_hour, to_hour):
    df_timeslice = df.ix[
        df.index.indexer_between_time(
            DT.time(from_hour), DT.time(to_hour),
            include_start=True, include_end=False)]
    # print(df_timeslice)
    #                     Buyer Product  Quantity
    # 2013-01-02 10:00:00   Joe       A        10
    # 2013-01-02 12:00:00   Joe       B         1
    return df_timeslice.groupby('Product').sum().sort(['Quantity'], ascending=False)

print(product_quantity(df, 0, 12))
#          Quantity
# Product          
# A              10

print(product_quantity(df, 12, 0))
#          Quantity
# Product          
# A              15
# B               3

如何在不使用平均值但使用自定义函数的情况下计算群组间统计数据(例如平均购买数量)?

def average_quantity_per_product(df):
    def myavg(grp):
        return grp['Quantity'].mean()
    return df.groupby('Product').apply(myavg)
print(average_quantity_per_product(df))
# Product
# A          6.25
# B          1.50

将一位买家与按日分组的其他买家进行比较:

def compare_buyers_with(df, name):
    def compare(grp):
        groups = grp.groupby('Buyer')
        total = groups['Quantity'].sum()
        return total-total.get(name, 0)
    dates = df.index.map(lambda d: d.date())
    return df.groupby([dates]).apply(compare)
print(compare_buyers_with(df, 'Carl'))
#             Buyer
# 2013-01-01  Carl     0
#             Mark    -8
# 2013-01-02  Carl     0
#             Joe      6
# Name: Quantity

查找产品尚未销售的日期:

def days_when_not_sold(df, name):
    dates = df.index.map(lambda d: d.date())
    def not_in(grp):
        return not np.any(name == grp['Product'])
    sales = df.groupby([dates]).apply(not_in)
    return sales.index.values[sales]
print(days_when_not_sold(df, 'A'))
# []
print(days_when_not_sold(df, 'C'))
# [2013-01-01 2013-01-02]