确定分组数据框中值的变化
Determine change in values in a grouped dataframe
假设这样的数据集(最初是从 .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)。
受此 post 的启发,我尝试了不同之处:
这是我到目前为止的想法(没有按预期工作):
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 数据帧。使用它们的解决方案会很棒。
你想要这样的东西吗?
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)
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
我认为您正在寻找 groupby
并通过 shift
;
进行比较
data.groupby('id')['value'].agg(lambda x: (x != x.shift(-1)).sum() - 1)
id
1 0
2 1
3 1
Name: value, dtype: int64
假设这样的数据集(最初是从 .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)。
受此 post 的启发,我尝试了不同之处:
这是我到目前为止的想法(没有按预期工作):
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 数据帧。使用它们的解决方案会很棒。
你想要这样的东西吗?
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)
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
我认为您正在寻找 groupby
并通过 shift
;
data.groupby('id')['value'].agg(lambda x: (x != x.shift(-1)).sum() - 1)
id
1 0
2 1
3 1
Name: value, dtype: int64