python - 给定销售前 5 年按每个卖家分组的汇总变量,不包括当年
问题描述
真的在为这种滚动计算而苦苦挣扎......非常感谢任何帮助。
对于数据框:
sale_year seller item_id mean_estimate sale_price deviation status
0 2019 bob 1 20000 11000 -9000 sold
1 2019 alice 2 35000 39000 4000 sold
2 2018 bob 3 15000 17000 2000 not sold
3 2017 alice 4 60000 120000 60000 sold
4 2017 alice 5 50000 80000 30000 sold
5 2017 alice 6 60000 120000 60000 sold
6 2017 alice 7 40000 120000 80000 sold
7 2017 bob 8 20000 27000 7000 sold
8 2017 alice 9 200000 175000 -25000 sold
9 2016 alice 10 100000 150000 50000 sold
10 2015 bob 11 75000 100000 25000 sold
11 2015 alice 12 100000 150000 50000 sold
12 2015 alice 13 10000 15000 5000 sold
13 2015 alice 14 100000 150000 50000 sold
13 2009 alice 15 150000 150000 0 sold
代码:
data = {
"sale_year": [2019, 2019, 2018, 2017, 2017, 2017, 2017, 2017, 2017, 2016, 2015, 2015, 2015, 2015, 2009],
"seller": ["bob", "alice", "bob", "alice", "alice", "alice", "alice", "bob", "alice", "alice", "bob", "alice", "alice", "alice", "alice"],
"item_id": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"mean_estimate": [20000, 35000, 15000, 60000, 50000, 60000, 40000, 20000, 200000, 100000, 75000, 100000, 10000, 100000, 150000],
"sale_price": [11000, 39000, 17000, 120000, 80000, 120000, 120000, 27000, 175000, 150000, 100000, 150000, 15000, 150000, 150000],
"deviation": [-9000, 4000, 2000, 60000, 30000, 60000, 80000, 7000, -25000, 50000, 25000, 50000, 5000, 50000, 0],
"status": ["sold", "sold", "not sold", "sold", "sold", "sold", "sold", "sold", "sold", "sold", "sold", "sold", "sold", "sold", "sold"]
}
test = pd.DataFrame(data)
我正在评估拍卖销售数据,并尝试为每个卖家计算其他变量,这些变量总结了他们在给定销售前 5 年的表现(不包括同一销售年份的销售)。
- 如果某件商品在 2019 年售出,则返回的变量应该是该卖家在 2014 年至 2018 年间(不包括 2019 年)售出的所有销售额的汇总。
- 如果一件商品在 2018 年售出,我希望变量与 2013 年至 2017 年之间的销售额相关,不包括 2018 年。
要生成的变量:
- 期间 mean_estimate 的平均值
- 期间偏差的平均值(偏差是 mean_estimate 和 sale_price 之间的差异)
- 时间段的 mean_estimate 值的标准偏差
- 期间偏差值的标准偏差
- 期间上市数量
- 期间售出的房源数量
- 销售比例 ( (listings - sales) / Listings )
- 已售房源数量的自然对数 (ln( 1 + sales ) )
现在我知道我可以使用 pandas .groupby() 和 agg 函数来生成各个年份的分组统计信息,例如
df.groupby([df.sale_year, df.seller]).mean_estimate.agg([np.mean, np.std])
我已经利用 smci 的有用建议来使用这样的.rolling()
方法:
alv = df.groupby(['seller']).rolling(5, min_periods=1).agg({'mean_estimate': ['mean', 'std', 'count'], 'deviation': ['mean', 'std', 'count']})
但是,问题在于它包括同一年发生的销售行(应该排除它们),以及我想要的时间段利用的是销售前的 5 年,而不是最近的 5 次交易(我的数据中有很多卖家的销售额超过 5000 次)。
示例输出:
ref_year seller avg_est avg_dev sd_est listings sales prop_sold ln_sales
2019 bob 36666 11333.3 33291.6 3 2 0.66 ln(3)
2019 alice 80000 40000 54543.5 9 9 1 ln(10)
2018 bob 47500 16000 38890.9 2 2 1 ln(3)
2018 alice 80000 40000 54542.5 9 9 1 ln(10)
... ... ... ... ... ... ... ... ...
2010 bob NaN NaN NaN NaN NaN NaN ln(1)
2010 alice 100000 50000 NA 1 1 1 ln(2)
理想情况下,我想坚持使用 pandas/base python,因为我想将上面的所有计算定义为一个函数以保存在库中以便于将来的 ETL。
预先感谢您的任何帮助
- 更新
我无法通过 Pandas groupby 和 agg 方法找到解决方案,但我已经成功按照@pygirl 的建议正确聚合并在 for 循环中执行计算
cols = ['index', 'sale_year', 'seller', 'realized_price','lot_status',
'mean_estimated_usd', 'deviation', 'mean_estimated_usd_log', 'deviation_rel_log',
'avgestimate', 'avgdeviation', 'sdestimate',
'sddeviation', 'numlistings', 'numlistings_sold', 'propbuyin',
'numlistings_log_prep', 'avgestimate_log_prep', 'cvestimate',
'cvdeviation']
appended_data = []
df_temp = pd.DataFrame(columns=cols)
for i in test.seller.unique():
row_sale_year = np.unique(test.sale_year.values)
row_seller = test.seller.iloc[0]
for year in row_sale_year:
# subset data to listingss relevant to a given seller and sale_year
alv_subset2 = (test.loc[(test.seller==row_seller) & (year-5 <= test.sale_year) & (test.sale_year< year)])
# filter down to only relevant columns
alv_subset2 = alv_subset2[['seller', 'sale_price', 'status', 'mean_estimate', 'deviation']]
alv_subset2['ref_year'] = year
alv_subset2 = alv_subset2.reset_index()
alv_subset2['avg_sale_price'] = np.mean(alv_subset2.sale_price)
alv_subset2['avgestimate'] = np.mean(alv_subset2.mean_estimate)
alv_subset2['numlistings'] = len(alv_subset2.status)
alv_subset2['numlistings_sold'] = len(alv_subset2[alv_subset2['status']=='sold'])
alv_subset2['propbuyin'] = (alv_subset2.numlistings-alv_subset2.numlistings_sold) / alv_subset2.numlistings.apply(lambda x: float(x))
alv_subset2['numlistings_log_prep'] = np.log(1 + alv_subset2.numlistings)
alv_subset2['avgestimate_log_prep'] = np.log(1 + alv_subset2.avgestimate)
for i in to_float:
alv_subset2[i] = alv_subset2[i].astype(float, errors = 'raise')
df_temp = df_temp.append(alv_subset2)
df_temp.drop(['index', 'status','realized_price', 'status', 'mean_estimated_usd', 'deviation', 'mean_estimated_usd_log', 'deviation_rel_log'], axis=1)
appended_data.append(alv_subset2)
# see pd.concat documentation for more info
df_temp = pd.concat(appended_data)
解决方案
您想 groupby然后使用pandasseller
使用 5 年滚动窗口进行聚合。rolling
a) 首先,制作sale_year
索引,这样rolling()
可以直接在索引上工作;通过升序(而不是降序)日期对 df 进行排序也很有帮助:
df = df.set_index('sale_year').sort_index()
b) 接下来,您可以使用df.rolling(window=5, min_periods=1)
. 窗口是索引使用的任何单位的“5”(此处为:年),其min_periods=1
论点是防止结果中出现虚假的恼人 NaN。
c) 然后,用 计算汇总统计信息 agg()
,将 'column_name':aggregation_function_or_name 传递给它。这些可以是函数、字符串名称pd.Series.mean
,例如 'mean' 或您自己的自定义函数或 lambda 函数:
df.groupby('seller').rolling(5, min_periods=1).agg({'mean_estimate': 'mean'})
mean_estimate
seller sale_year
alice 2017 60000.000000
2017 130000.000000
2019 98333.333333
bob 2015 75000.000000
2016 87500.000000
2017 65000.000000
2018 52500.000000
d) 然后将所有其他 'field':'function' 条目添加到聚合字典中。pd.RollingGroupby
没有size
与 base 不同的方法GroupBy
,实际上不支持 RollingGroupby 上的大多数聚合方法,因此您必须编写其中一些方法。
推荐阅读
- python - 我在修改玩具 scikit-learn gridsearchCV 示例时收到警告“用户警告:一个或多个测试分数是非限定的”
- javascript - 如果变量为真,则不显示重定向警告
- ios - UIButton 和临时 UIMenu
- ruby-on-rails - 如何让 postgres 从 big sur 开始?
- javascript - 一个在所有整数中出现频率相同的数
- reactjs - TypeError: prevDeps is undefined 尝试在 React 中添加 Material UI 组件时出错
- swift - 尝试在 Swift Playground (Xcode 12.4) 中加载文件时出现 EXC_BAD_INSTRUCTION
- python - 相同元素的索引是否相同?
- javascript - 有没有办法获取一堆图像(在这种情况下为 .png)并上传数据点以创建线条重叠区域的热图?
- vue.js - 后端应用程序中的 Vue.js 反应性功能?