【问题标题】:Take the differences between groups of varying size in pandas groupby在 pandas groupby 中取不同大小的组之间的差异
【发布时间】:2019-06-21 14:06:11
【问题描述】:

我需要计算如下数据中连续时间组之间的差异

from io import StringIO

import pandas as pd

strio = StringIO("""\
               date  feat1         feat2  value
2016-10-15T00:00:00      1             1    0.0
2016-10-15T00:00:00      1             2    1.0
2016-10-15T00:00:00      2             1    2.0
2016-10-15T00:00:00      2             2    3.0
2016-10-15T00:01:00      1             1    8.0
2016-10-15T00:01:00      1             2    5.0
2016-10-15T00:02:00      1             1    8.0
2016-10-15T00:02:00      1             2   12.0
2016-10-15T00:02:00      2             1   10.0
2016-10-15T00:02:00      2             2   11.0
2016-10-15T00:03:00      1             1   12.0
2016-10-15T00:03:00      1             2   13.0
2016-10-15T00:03:00      2             1   14.0
2016-10-15T00:03:00      2             2   15.0""")

我可以使用 xarray 库来做到这一点

df = pd.read_table(strio, sep='\s+')
dims = df.columns.values[:3].tolist()
df.set_index(dims, inplace=True) # needed to convert to xarray dataset
dataset = df.to_xarray()
diff_time = dataset.diff(dim=dims[0]) # take the diff in time
print(diff_time.to_dataframe().reset_index())

打印

                   date  feat1  feat2  value
0   2016-10-15T00:01:00      1      1    8.0
1   2016-10-15T00:01:00      1      2    4.0
2   2016-10-15T00:01:00      2      1    NaN
3   2016-10-15T00:01:00      2      2    NaN
4   2016-10-15T00:02:00      1      1    0.0
5   2016-10-15T00:02:00      1      2    7.0
6   2016-10-15T00:02:00      2      1    NaN
7   2016-10-15T00:02:00      2      2    NaN
8   2016-10-15T00:03:00      1      1    4.0
9   2016-10-15T00:03:00      1      2    1.0
10  2016-10-15T00:03:00      2      1    4.0
11  2016-10-15T00:03:00      2      2    4.0

所以在 2016-10-15T00:01:00 瞬间,我有 feat1:2 缺少相关差异是 nan

如何以矢量化方式在纯熊猫中执行此操作?使用 nan 填充构建原始数据框(因此组大小相同)是一种选择,但应避免

一个笨拙的方法是:

dfs = []
for k, v in zip(itertools.islice(df.groupby(level=0).groups.values(), 1, None),
                df.groupby(level=0).groups.values()):
    # print(df.loc(axis=0)[k.values] , df.loc(axis=0)[v.values])
    diff = df.loc(axis=0)[k.values].reset_index(level=0, drop=True) - \
           df.loc(axis=0)[v.values].reset_index(level=0, drop=True)
    diff = pd.concat([diff], keys=[k.values[0][0]], names=['date'])
    dfs.append(diff)
print(pd.concat(dfs).reset_index())

它确实打印相同的输出,但它不是矢量化的

【问题讨论】:

  • 您能解释一下输出背后的逻辑吗? feat1feat2 有什么关系?每个value 4 是因为您试图获取每个date 组的大小吗?如果是这样,这是否接近您正在寻找的内容:df['value'] = df['date'].map(df.groupby('date').size())
  • Nope 4 是相同(feat1,feat2)子数据帧(每个组)之间的差异。所以这一行2016-10-15T00:01:00 1 1 4.0 减去那一行(前一个实例相同的feat1 和feat2)2016-10-15T00:01:00 1 1 4.0 - 当下一个或前一个实例中没有feat1 或feat2 时,我自然会得到NaN
  • 自我说明:删除索引:stackoverflow.com/a/17085044/281545并添加回:stackoverflow.com/a/42094658/281545,以解释问题中的循环代码

标签: python pandas pandas-groupby python-xarray


【解决方案1】:

更新的解决方案:

df.unstack(0)['value']\
  .diff(axis=1)\
  .dropna(how='all', axis=1)\
  .unstack([0,1])\
  .rename('value')\
  .reset_index()

输出:

                   date  feat1  feat2  value
0   2016-10-15T00:01:00      1      1    8.0
1   2016-10-15T00:01:00      1      2    4.0
2   2016-10-15T00:01:00      2      1    NaN
3   2016-10-15T00:01:00      2      2    NaN
4   2016-10-15T00:02:00      1      1    0.0
5   2016-10-15T00:02:00      1      2    7.0
6   2016-10-15T00:02:00      2      1    NaN
7   2016-10-15T00:02:00      2      2    NaN
8   2016-10-15T00:03:00      1      1    4.0
9   2016-10-15T00:03:00      1      2    1.0
10  2016-10-15T00:03:00      2      1    4.0
11  2016-10-15T00:03:00      2      2    4.0

详情:

创建一个三级MultiIndex后,首先让我们unstack level 0,date,它将日期从行移动到列,然后在列上使用diff,最后使用dropna删除第一个日期,其中整个列是nan和unstack feat1和feat2 重新创建多索引并转换回数据帧。

【讨论】:

  • 哇,令人印象深刻 - 我在尝试消化时接受(尤其是这个 transform(lambda x: x.iloc[0]).unstack(0).diff(axis=1) 部分,unstack 逃脱了我)
  • 让我将步骤添加到解决方案中。
  • 基本上,我正在重塑数据框,让我可以轻松地在列上使用 diff 并重塑回原始形式。
  • 唯一的要求是日期确实是有序的 - 但可能存在差距 - 循环解决方案仍然可以工作,尽管笨拙得像地狱
  • 是的 - 谢谢 - 随意删除初始解决方案,因为它并没有真正解决它,可以对unstack(0) 使用一些解释,这是它的要点 - 所以这将“日期”级别移动到列,然后我们区分列 IIUC
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 2019-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-16
相关资源
最近更新 更多