首页 > 解决方案 > 给定销售前 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 年的表现(不包括同一销售年份的销售)。

要生成的变量:

  1. 期间 mean_estimate 的平均值
  2. 期间偏差的平均值(偏差是 mean_estimate 和 sale_price 之间的差异)
  3. 时间段的 mean_estimate 值的标准偏差
  4. 期间偏差值的标准偏差
  5. 期间上市数量
  6. 期间售出的房源数量
  7. 销售比例 ( (listings - sales) / Listings )
  8. 已售房源数量的自然对数 (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)



标签: pythonpandasdataframepandas-groupbyetl

解决方案


您想 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 上的大多数聚合方法,因此您必须编写其中一些方法。


推荐阅读