计算数据帧组内的差异

8on*_*ne6 31 python pandas

假设我有一个包含3列的数据框:Date,Ticker,Value(没有索引,至少可以开始).我有很多日期和许多代码,但每个(ticker, date)元组都是独一无二的.(但显然相同的日期会出现在很多行中,因为它会存在多个代码,并且同一个代码将显示在多行中,因为它将存在很多日期.)

最初,我的行按特定顺序排列,但未按任何列排序.

我想计算每个股票代码的第一个差异(每日更改)(按日期排序),并将它们放在我的数据框中的新列中.鉴于这种背景,我不能简单地这样做

df['diffs'] = df['value'].diff()
Run Code Online (Sandbox Code Playgroud)

因为相邻的行不是来自同一个自动收报机.排序如下:

df = df.sort(['ticker', 'date'])
df['diffs'] = df['value'].diff()
Run Code Online (Sandbox Code Playgroud)

没有解决问题,因为会有"边界".即在那之后,一个股票代码的最后一个值将高于下一个股票代码的第一个值.然后计算差异会使两个代码之间产生差异.我不想要这个.我希望每个自动收报机的最早日期NaN在其差异列中结束.

这似乎是一个明显的使用时间,groupby但无论出于何种原因,我似乎无法让它正常工作.为了清楚起见,我想执行以下过程:

  1. 根据它们对行进行分组 ticker
  2. 在每个组中,按行分类 date
  3. 在每个已排序的组中,计算value列的差异
  4. 将这些差异放入新diffs列中的原始数据框中(理想情况下,保留原始数据框顺序).

我不得不想象这是一个单行.但是我错过了什么?


编辑于2013-12-17的晚上9点

好的...一些进展.我可以执行以下操作来获取新的数据帧:

result = df.set_index(['ticker', 'date'])\
    .groupby(level='ticker')\
    .transform(lambda x: x.sort_index().diff())\
    .reset_index()
Run Code Online (Sandbox Code Playgroud)

但是,如果我理解groupby的机制,我的行现在将首先排序ticker,然后排序date.那是对的吗?如果是这样,我是否需要进行合并以附加差异列(当前位于result['current']原始数据框中df

beh*_*uri 28

做你自己描述的事情并不容易

df.sort(['ticker', 'date'], inplace=True)
df['diffs'] = df['value'].diff()
Run Code Online (Sandbox Code Playgroud)

然后更正边框:

mask = df.ticker != df.ticker.shift(1)
df['diffs'][mask] = np.nan
Run Code Online (Sandbox Code Playgroud)

保持你可能idx = df.index在开始时做的原始索引,然后在最后你可以做df.reindex(idx),或者如果它是一个巨大的数据帧,执行操作

df.filter(['ticker', 'date', 'value'])
Run Code Online (Sandbox Code Playgroud)

然后join是最后的两个数据帧.

编辑:或者,(虽然仍未使用groupby)

df.set_index(['ticker','date'], inplace=True)
df.sort_index(inplace=True)
df['diffs'] = np.nan 

for idx in df.index.levels[0]:
    df.diffs[idx] = df.value[idx].diff()
Run Code Online (Sandbox Code Playgroud)

对于

   date ticker  value
0    63      C   1.65
1    88      C  -1.93
2    22      C  -1.29
3    76      A  -0.79
4    72      B  -1.24
5    34      A  -0.23
6    92      B   2.43
7    22      A   0.55
8    32      A  -2.50
9    59      B  -1.01
Run Code Online (Sandbox Code Playgroud)

这将产生:

             value  diffs
ticker date              
A      22     0.55    NaN
       32    -2.50  -3.05
       34    -0.23   2.27
       76    -0.79  -0.56
B      59    -1.01    NaN
       72    -1.24  -0.23
       92     2.43   3.67
C      22    -1.29    NaN
       63     1.65   2.94
       88    -1.93  -3.58
Run Code Online (Sandbox Code Playgroud)


8on*_*ne6 13

好.很多人都在考虑这个问题,我认为这是我最喜欢的上述解决方案和一些游戏的组合.原始数据存在于df:

df.sort(['ticker', 'date'], inplace=True)

# for this example, with diff, I think this syntax is a bit clunky
# but for more general examples, this should be good.  But can we do better?
df['diffs'] = df.groupby(['ticker'])['value'].transform(lambda x: x.diff()) 

df.sort_index(inplace=True)
Run Code Online (Sandbox Code Playgroud)

这将完成我想要的一切.而我真正喜欢的是它可以推广到你想要应用比复杂更复杂的函数的情况diff.特别是,您可以做一些事情,比如lambda x: pd.rolling_mean(x, 20, 20)制作一个滚动方式的列,您不必担心每个自动收报机的数据被任何其他自动收报机的数据损坏(groupby为您处理...).

所以这是我留下的问题......为什么下面的工作不适用于开始的行df['diffs']:

df['diffs'] = df.groupby[('ticker')]['value'].transform(np.diff)
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我得到一个diffs满是0的列.有什么想法吗?


rhn*_*n89 5

# Make sure your data is sorted properly
df = df.sort_values(by=['group_var', 'value'])

# only take diffs where next row is of the same group
df['diffs'] = np.where(df.group_var == df.group_var.shift(1), df.value.diff(), 0)
Run Code Online (Sandbox Code Playgroud)

解释: 在此处输入图片说明


小智 5

我知道这是一个老问题,所以我假设这个功能当时不存在。但对于那些现在有这个问题的人来说,这个解决方案效果很好:

df.sort_values(['ticker', 'date'], inplace=True)
df['diffs'] = df.groupby('ticker')['value'].diff()
Run Code Online (Sandbox Code Playgroud)

为了恢复到原来的顺序,你可以使用

df.sort_index(inplace=True)
Run Code Online (Sandbox Code Playgroud)