Jupyter Pandas - 丢弃平均超过阈值的项目
Jupyter Pandas - dropping items which have average over a threshold
我有一个包含商品及其价格的数据框,如下所示:
╔══════╦═════╦═══════╗
║ 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()
过滤原始数据框以仅包含价格范围内的商品行
filtered_df = df[df.ItemID.isin(items_in_price_range)]
`
有更好的方法吗?
使用 GroupBy.transform
for mean
s per groups with same size like original, so possible filter out by 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
让我告诉你我会怎么做(vaex 主要作者),尽管 就快到了。
让我们首先生成数据帧:
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
我有一个包含商品及其价格的数据框,如下所示:
╔══════╦═════╦═══════╗
║ 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()
过滤原始数据框以仅包含价格范围内的商品行
filtered_df = df[df.ItemID.isin(items_in_price_range)] ` 有更好的方法吗?
使用 GroupBy.transform
for mean
s per groups with same size like original, so possible filter out by 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
让我告诉你我会怎么做(vaex 主要作者),尽管
让我们首先生成数据帧:
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