1

我有一个包含物品及其价格的数据框,如下所示: ╔══════╦═════╦═══════╗ ║ Item ║ Day ║ Price ║ ╠══════╬═════╬═══════╣ ║ A ║ 1 ║ 10 ║ ║ B ║ 1 ║ 20 ║ ║ C ║ 1 ║ 30 ║ ║ D ║ 1 ║ 40 ║ ║ A ║ 2 ║ 100 ║ ║ B ║ 2 ║ 20 ║ ║ C ║ 2 ║ 30 ║ ║ D ║ 2 ║ 40 ║ ║ A ║ 3 ║ 500 ║ ║ B ║ 3 ║ 25 ║ ║ C ║ 3 ║ 35 ║ ║ D ║ 3 ║ 1000 ║ ╚══════╩═════╩═══════╝

我想从这个 df 中排除所有行,其中项目的平均价格超过 200。所以过滤后的 df 应该如下所示: ╔══════╦═════╦═══════╗ ║ Item ║ Day ║ Price ║ ╠══════╬═════╬═══════╣ ║ B ║ 1 ║ 20 ║ ║ C ║ 1 ║ 30 ║ ║ B ║ 2 ║ 20 ║ ║ C ║ 2 ║ 30 ║ ║ B ║ 3 ║ 25 ║ ║ C ║ 3 ║ 35 ║ ╚══════╩═════╩═══════╝

我是python和pandas的新手,但第一步是考虑这样的事情来获得平均价格的新df:avg_prices_df = df.groupby('ItemID').Price.mean().reset_index 然后不知道如何从那里开始。甚至不确定第一步是否正确。

更复杂的是,我使用 vaex 读取 ndf5 格式的数据,因为我有超过 4 亿行。

非常感谢您的任何建议。

编辑:所以我得到了以下代码,尽管我确信它没有被优化..

`

创建 ItemID 及其平均价格的数据框

df_item_avg_price = df.groupby(df.ItemID, agg=[vaex.agg.count('ItemID'), vaex.agg.mean('Price')])

按平均价格阈值过滤这个新数据框

df_item_avg_price = (df_item_avg_price[df_item_avg_price["P_r_i_c_e_mean"] <= 50000000])

创建平均价格低于阈值的 ItemID 列表

items_in_price_range = df_item_avg_price['ItemID'].tolist()

过滤原始数据框以仅包含价格范围内的项目的行

filters_df = df[df.ItemID.isin(items_in_price_range)] `有更好的方法吗?

4

2 回答 2

1

使用与原始大小相同的每个组GroupBy.transformmeans,因此可能会被所有组过滤掉boolean indexing,意味着不太像200

avg_prices_df = df[df.groupby('Item')['Price'].transform('mean') < 200]

另一个解决方案DataFrameGroupBy.filter

avg_prices_df = df.groupby('Item').filter(lambda x: x['Price'].mean() < 200)

print (avg_prices_df)
   Item  Day  Price
1     B    1     20
2     C    1     30
5     B    2     20
6     C    2     30
9     B    3     25
10    C    3     35

print (df.groupby('Item')['Price'].transform('mean'))
0     203.333333
1      21.666667
2      31.666667
3     360.000000
4     203.333333
5      21.666667
6      31.666667
7     360.000000
8     203.333333
9      21.666667
10     31.666667
11    360.000000
Name: Price, dtype: float64

vaex的解决方案:

df_item_avg_price = df.groupby(df.ItemID).agg({'Price' : 'mean'})
df_item_avg_price = (df_item_avg_price[df_item_avg_price["Price"] <= 200])

df = df_item_avg_price.drop(['Price']).join(df, on='ItemID')
print (df)
  ItemID  Day  Price
0      B    1     20
1      B    2     20
2      B    3     25
3      C    1     30
4      C    2     30
5      C    3     35
于 2019-12-08T07:19:06.807 回答
0

让我向您展示我将如何做到这一点(vaex 主要作者),尽管Jupyter Pandas - 丢弃平均超过阈值的项目几乎就在那里。

让我们首先生成数据框:

data = [["A", 1,  10],
["A", 1,  10],
["B", 1,  20],
["C", 1,  30],
["D", 1,  40],
["A", 2, 100],
["B", 2,  20],
["C", 2,  30],
["D", 2,  40],
["A", 3, 500],
["B", 3,  25],
["C", 3,  35],
["D", 3, 1000]]

import vaex
df = vaex.from_arrays(Item=[k[0] for k in data], Day=[k[1] for k in data], Price=[k[2] for k in data])
print(df)
#    Item    Day    Price
0    A       1      10
1    A       1      10
2    B       1      20
3    C       1      30
4    D       1      40
...  ...     ...    ...
8    D       2      40
9    A       3      500
10   B       3      25
11   C       3      35
12   D       3      1000

并生成具有平均价格的数据框:

df_avg_price = df.groupby(df.Item, agg={"Price": 'mean'})
print(df_avg_price)
#  Item       Price
0  A       155
1  B        21.6667
2  C        31.6667
3  D       360

最新版本的 vaex 不喜欢重新加入,因为两个数据框中的名称(Item)重复,尽管列被加入(这在 master 中修复(https://github.com/vaexio/vaex),但是我们可以通过为正确的数据框使用前缀来解决这个问题。

df2 = df.join(df_avg_price, on='Item', rprefix='avg')
df2 = df2[df2.avgPrice < 200]  # notice the prefix

如果你想摆脱其他列:

df2 = df2[['Item', 'Day', 'Price']]  # only get the rows we want
print(df2)
#  Item      Day    Price
0  A           1       10
1  A           1       10
2  B           1       20
3  C           1       30
4  A           2      100
5  B           2       20
6  C           2       30
7  A           3      500
8  B           3       25
9  C           3       35
于 2019-12-11T09:19:21.460 回答