如何计算相同ID的月收入差异

时间:2018-06-19 23:11:11

标签: pandas dataframe

以下数据框显示了几年中两家商店(shop_id=11shop_id=15)的月收入:

data = { 'shop_id' : [   11,    15,    15,    15,    11,   11 ],
         'month'   : [    1,     1,     2,     3,     2,    3 ],
         'year'    : [ 2011,  2015,  2015,  2015,  2014, 2014 ],
         'revenue' : [11000,  5000,  4500,  5500, 10000, 8000]
       }

df = pd.DataFrame(data)
df = df[['shop_id', 'month', 'year', 'revenue']]
display(df)

enter image description here

您会注意到shop_id=11在2011年(1月)只有一个条目,而shop_id=15在2015年(1月,2月和3月)只有几个条目。不过,有趣的是,第一家商店在2014年还有更多条目:

enter image description here

我正在尝试优化自定义功能(与.apply()一起使用),以创建名为diff_revenue的新功能:此功能显示了每个商店的上个月收入变化:

enter image description here

我想对如何生成diff_revenue中的某些值提供一些解释:

  • 第一个单元格的值为 0 (红色),因为没有shop_id=11的先前信息;
  • 第二个单元格也是 0 (橙色),原因相同:shop_id=15没有先前的信息;
  • 第三个单元格为 500 (绿色),因为从该商店的最后一个条目(2015年1月)到当前单元格的收入(2015年2月)的变化是500个特朗普。 / li>
  • 第5个单元格为 1000 (深蓝色),因为从该商店的最后一个条目(2011年1月)到当前单元格的收入(2014年2月)的变化为1000特朗普。 / li>

我不是熊猫专家,并且想知道熊猫神是否知道更好的方法。我必须使用的DataFrame很大(+ 1M观察),而我目前的方法太慢了。我正在寻找一种更快的替代方法,或者可能是更具可读性的方法。

1 个答案:

答案 0 :(得分:2)

您或多或少希望在'Revenue'列上使用Series.diff,但需要做一些其他事情:

  • 排序以确保您的DataFrame按时间顺序排列(以后可以撤消此操作)
  • groupby上执行'shop_id'以进行组级操作
  • 取绝对值,因为您不想在正负之间进行区分

在代码方面:

# sort the values so they're in order when we perform a groupby
df = df.sort_values(by=['year', 'month'])

# perform a groupby on 'shop_id' and get the row-wise difference within each group
df['diff_revenue'] = df.groupby('shop_id')['revenue'].diff()

# fill NA as zero (no previous info), take absolute value, convert float -> int
df['diff_revenue'] = df['diff_revenue'].fillna(0).abs().astype('int')

# revert to original order
df = df.sort_index()

结果输出:

   shop_id  month  year  revenue  diff_revenue
0       11      1  2011    11000             0
1       15      1  2015     5000             0
2       15      2  2015     4500           500
3       15      3  2015     5500          1000
4       11      2  2014    10000          1000
5       11      3  2014     8000          2000

修改

不太直接的解决方案,但性能可能更高:

# sort the values so they're chronological order by shop_id
df = df.sort_values(by=['shop_id', 'year', 'month'])

# take the row-wise difference ignoring changes in shop_id
df['diff_revenue'] = df['revenue'].diff()

# zero out locations where shop_id changes (no previous info)
df.loc[df['shop_id'] != df['shop_id'].shift(), 'diff_revenue'] = 0

# Take the absolute value, convert float -> int
df['diff_revenue'] = df['diff_revenue'].abs().astype('int')

# revert to original order
df = df.sort_index()