【问题标题】:Fill in lookup table in Python using pandas dataframe and aggregate function使用 pandas 数据框和聚合函数在 Python 中填写查找表
【发布时间】:2021-10-08 14:41:38
【问题描述】:

我有一个 pandas 数据框,其中包含不同日期的(商店、产品、价格)信息。

df = pd.DataFrame(data={'day': [1, 2, 3, 1, 2, 3, 2, 4, 5, 2, 4, 5, 2, 4, 5, 2, 4, 5],
                        'shop': ['a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'c'],
                        'product': ['x', 'x', 'x', 'y', 'y', 'y', 'x', 'x', 'x', 'z', 'z', 'z', 'y', 'y', 'y', 'z', 'z', 'z'],
                        'price': [0, 1, 2, 2, 4, 6, 1, 2, 3, 0, 1, 1, 1, 1, 0, 2, 2, 2]})

我想制作一个查找表,为每个(商店、产品)组合提供最近两天的平均价格。

例如,给定店铺'a'和产品'y',价格分别是2、4和6,那么查找表中的结果应该是4和6的平均值,也就是5。

预期的结果是下面的嵌套字典:

{'a': {'x': 1.5, 'y': 5.0},
 'b': {'x': 2.5, 'z': 1.0},
 'c': {'y': 0.5, 'z': 2.0}}

我想出了两个解决方案。

#解决方案1:嵌套for循环

lookup = {}
for categ_1 in df['shop'].unique():
    df_1 = df[df['shop'] == categ_1]
    lookup[categ_1] = {}
    for categ_2 in df_1['product'].unique():
        df_2 = df_1[df_1['product'] == categ_2]
        res = df_2.iloc[-2:,:]['price'].mean()
        lookup[categ_1][categ_2] = res

#Solution 2:过滤(商店、产品)的独特组合并对其进行迭代

lookup = {}
for i, row in df[['shop', 'product']].drop_duplicates().iterrows():
    mask = ((df['shop'] == row['shop']) & (df['product'] == row['product']))
    _df = df[mask]
    res = _df.iloc[-2:,:]['price'].mean()
    try:
        lookup[row['shop']].update({row['product']: res})
    except KeyError:
        lookup[row['shop']] = {row['product']: res}

虽然我发现解决方案 2 更优雅,但解决方案 1 更快。

  • 解决方案 1:每个循环 7.57 毫秒 ± 1.25 毫秒(平均值 ± 标准偏差,7 次运行,每次 100 次循环)
  • 解决方案 2:每个循环 9.3 毫秒 ± 1.04 毫秒(7 次运行的平均值 ± 标准偏差,每次 100 次循环)

我的实际数据框包含要迭代的更多列和更多行,因此如果可能的话,我希望避免像解决方案 1 中那样嵌套 for 循环,但也是比解决方案 2 更快的解决方案。

如果您能改进其中一个解决方案或找到更好的解决方案,我会很高兴

谢谢

【问题讨论】:

    标签: python pandas dataframe dictionary lookup


    【解决方案1】:

    Pandas 有一个 groupby 函数非常适合这个。

    lookup = df.groupby(['shop', 'product'])
    

    这会给你一个 groupby 对象。接下来的挑战是如何根据过去两天聚合您的列,因为这并不是 GroupBy 固有的。您可以创建一个 lambda 函数来获取每个价格列表中的最后两项并计算平均值。

    df.sort_values(by='day', ascending=True, inplace=True)
    avg_func = lambda x: sum(x[-2:])/2
    lookup = df.groupby(['shop', 'product']).agg({'price': avg_func})
    

    输出:

    shop product       
    a    x          1.5
         y          5.0
    b    x          2.5
         z          1.0
    c    y          0.5
         z          2.0
     
    

    【讨论】:

    • 这很好用,谢谢!有没有一种有效的方法可以从您的数据框输出中获取我期望的字典?
    • 是的,您可以在 DataFrame 上调用 .to_dict() 方法。
    猜你喜欢
    • 1970-01-01
    • 2017-06-23
    • 2021-11-14
    • 2019-05-20
    • 2016-11-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多