【问题标题】:Determine change in values in a grouped dataframe确定分组数据框中值的变化
【发布时间】:2018-02-27 13:19:23
【问题描述】:

假设这样的数据集(最初是从 .csv 中读取的):

data = pd.DataFrame({'id': [1,2,3,1,2,3],
                     'time':['2017-01-01 12:00:00','2017-01-01 12:00:00','2017-01-01 12:00:00',
                          '2017-01-01 12:10:00','2017-01-01 12:10:00','2017-01-01 12:10:00'],
                     'value': [10,11,12,10,12,13]})

=>

    id  time                    value
0   1   2017-01-01 12:00:00     10
1   2   2017-01-01 12:00:00     11
2   3   2017-01-01 12:00:00     12
3   1   2017-01-01 12:10:00     10
4   2   2017-01-01 12:10:00     12
5   3   2017-01-01 12:10:00     13

每个观察期内所有 ID 的时间都相同。该系列以这样的方式进行许多观察,即每十分钟一次。

我想要value 列中连续时间之间 id 的总更改数。例如:对于 id=1,没有变化(结果:0)。对于 id=2 有一个变化(结果:1)。 受这篇文章的启发,我尝试了差异: Determining when a column value changes in pandas dataframe

这是我迄今为止提出的(没有按预期工作):

data = data.set_index(['id', 'time']) # MultiIndex 
grouped = data.groupby(level='id') 
data['diff'] = grouped['value'].diff()
data.loc[data['diff'].notnull(), 'diff'] = 1
data.loc[data['diff'].isnull(), 'diff'] = 0
grouped['diff'].sum()

但是,这只是每个 id 出现次数的总和。

由于我的数据集很大(并且不适合内存),因此解决方案应该尽可能快。 (这就是我在 id + time 上使用 MultiIndex 的原因。我期望显着加快速度,因为最佳情况下不需要再打乱数据。)

此外,我遇到了与 pandas dfs 非常相似的 dask 数据帧。利用它们的解决方案会很棒。

【问题讨论】:

  • 重要:一个时隙中的一组读数可以有多个读数与同一个ID关联吗?
  • @COLDSPEED:不,这些是观察结果。对于每个时间点,每个 id 最多有一个值。
  • 好吧,在这种情况下,你有 3 个很好的答案给你同样的东西。请选择最有帮助的解决方案并接受它。
  • 如果您有一个项目从 10 变为 11,然后从 11 变为 10,则正确的输出将是 2,但 len(set(x)) - 1 将只记录 1。这就是您描述的方式问题陈述,这就是我们解释和回答它的方式。
  • 您可以尝试在 numba 标签中提问,看看您是否会得到任何响应或加速。怀疑熊猫在这里可以做更多了。

标签: python pandas dataframe group-by pandas-groupby


【解决方案1】:

你想要这样的东西吗?

data.groupby('id').value.apply(lambda x: len(set(x)) - 1)

你得到

id
1    0
2    1
3    1

编辑:正如@COLDSPEED 提到的,如果要求将更改捕获回某个值,请使用

data.groupby('id').value.apply(lambda x: (x != x.shift()).sum() - 1)

【讨论】:

    【解决方案2】:
    data.groupby('id').value.agg(lambda x : (x.diff()!=0).sum()).add(-1)
    id
    1    0
    2    1
    3    1
    Name: value, dtype: int64
    

    另一个使用pct_change

    data.groupby('id').value.apply(lambda x : (x.pct_change()!=0).sum()).add(-1)
    Out[323]: 
    id
    1    0
    2    1
    3    1
    Name: value, dtype: int64
    

    【讨论】:

    • 啊,我知道还有另一种 diff 方法。等你来找它+1
    • @cᴏʟᴅsᴘᴇᴇᴅ 想不通,哈哈~等你更新~:)
    【解决方案3】:

    我认为您正在寻找groupbyshift 的比较;

    data.groupby('id')['value'].agg(lambda x: (x != x.shift(-1)).sum() - 1) 
    
    id
    1    0
    2    1
    3    1
    Name: value, dtype: int64
    

    【讨论】:

    • @Vaishali 我想我的答案和你的一样。我只会删除它。你怎么看?
    • 没关系,我个人觉得这两个都是几秒钟内给出的有效答案。所以只要没有人抄袭,就很酷:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多