【问题标题】:Pandas find all combinations of rows under a budgetPandas 在预算范围内找到所有行组合
【发布时间】:2019-09-26 14:57:29
【问题描述】:

我正在尝试找出一种方法来确定 DataFrame 中低于预算的所有可能的行组合,所以假设我有一个这样的数据框:

data = [['Bread', 9, 'Food'], ['Shoes', 20, 'Clothes'], ['Shirt', 15, 'Clothes'], ['Milk', 5, 'Drink'], ['Cereal', 8, 'Food'], ['Chips', 10, 'Food'], ['Beer', 15, 'Drink'], ['Popcorn', 3, 'Food'], ['Ice Cream', 6, 'Food'], ['Soda', 4, 'Drink']]
df = pd.DataFrame(data, columns = ['Item', 'Price', 'Type'])
df

数据

Item       Price  Type
Bread      9      Food
Shoes      20     Clothes
Shirt      15     Clothes
Milk       5      Drink
Cereal     8      Food
Chips      10     Food
Beer       15     Drink
Popcorn    3      Food
Ice Cream  6      Food
Soda       4      Drink

我想找到我可以在特定预算下购买的每一种组合,比如这个例子中的 35 美元,而每种类型只买一种。我想获得一个新的数据框,该数据框由每个组合的行组成,这些组合与自己列中的每个项目一起使用。

我尝试使用 itertools.product 来完成,但这可以组合和添加列,但我真正需要做的是根据另一列中的值组合和添加特定列。我现在有点难过。

感谢您的帮助!

【问题讨论】:

标签: python pandas dataframe itertools


【解决方案1】:

这是一种使用来自itertoolspd.concatpowerset 配方的方法

from itertools import chain, combinations

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

df_groups = pd.concat([df.reindex(l).assign(grp=n) for n, l in 
                       enumerate(powerset(df.index)) 
                       if (df.loc[l, 'Price'].sum() <= 35)])

输出单个数据框,其中包含满足 35 美元条件的产品组:

          Item  Price     Type  grp
0       Bread      9     Food    1
1       Shoes     20  Clothes    2
2       Shirt     15  Clothes    3
3        Milk      5    Drink    4
4      Cereal      8     Food    5
..        ...    ...      ...  ...
3        Milk      5    Drink  752
4      Cereal      8     Food  752
7     Popcorn      3     Food  752
8   Ice Cream      6     Food  752
9        Soda      4    Drink  752

总共有多少种方法可以满足 35 美元的预算?

df_groups['grp'].nunique()

输出:

258

详情:

这里使用了一些技巧/方法。首先,我们使用数据框的索引使用powerset 创建行或项目组。接下来,我们使用enumerate 来识别每个组,并使用assign 在数据框中创建一个新列,该列具有来自枚举的组号。

修改以捕获每种类型不超过一种:

df_groups = pd.concat([df.reindex(l).assign(grp=n) for n, l in 
                       enumerate(powerset(df.index)) 
                       if ((df.loc[l, 'Price'].sum() <= 35) & 
                           (df.loc[l, 'Type'].value_counts()==1).all())])

多少组?

df_groups['grp'].nunique()
62

为每种类型准确获取一个:

df_groups = pd.concat([df.reindex(l).assign(grp=n) for n, l in 
                       enumerate(powerset(df.index)) 
                       if ((df.loc[l, 'Price'].sum() <= 35) & 
                           (df.loc[l, 'Type'].value_counts()==1).all()&
                           (len(df.loc[l, 'Type']) == 3))])

多少组?

df_groups['grp'].nunique()
21

【讨论】:

  • 太棒了!我怎么能限制它并要求它每种类型只有一项?
  • @Emac 您需要修改列表理解的 if 部分。查看更新。
  • 漂亮!谢谢楼主,很快就搞定了!干得好。
  • @Emac 谢谢。编码愉快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多