【问题标题】:Add a dummy indicating change between consecutive rows in grouped dataframe添加一个虚拟指示分组数据帧中连续行之间的变化
【发布时间】:2017-09-26 06:30:31
【问题描述】:

这是对我之前的问题here 的跟进。 假设这样的数据集(最初是从 .csv 读取的):

data = pd.DataFrame({'id': [1,2,3,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',
                            '2017-01-01 12:20:00','2017-01-01 12:20:00','2017-01-01 12:20:00'],
                     'values': [10,11,12,10,12,13,10,13,13]})

data = data.set_index('id')

=>

    id  time                    values
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
6   1   2017-01-01 12:20:00     10
7   2   2017-01-01 12:20:00     13
8   3   2017-01-01 12:20:00     13

每个观察期内所有 ID 的时间都相同。该系列以这样的方式进行许多观察,即每十分钟一次。 之前学习了如何获取每个id在两个连续周期之间values的变化总数:

data.groupby(data.index).values.apply(lambda x: (x != x.shift()).sum() - 1)

这很好用,而且速度非常快。现在,我有兴趣在 df 中添加一个新列。如果当前行和上一行之间有变化,它应该是一个虚拟指示 values 中的每一行。因此,结果如下:

=>

    id  time                    values    change
0   1   2017-01-01 12:00:00     10        0
1   2   2017-01-01 12:00:00     11        0
2   3   2017-01-01 12:00:00     12        0
3   1   2017-01-01 12:10:00     10        0
4   2   2017-01-01 12:10:00     12        1
5   3   2017-01-01 12:10:00     13        1
6   1   2017-01-01 12:20:00     10        0
7   2   2017-01-01 12:20:00     13        1
8   3   2017-01-01 12:20:00     13        0

在折腾之后,我想出了一个解决方案。但是,它真的很慢。它不会在我相当大的实际数据集上运行:

def calc_change(x):
    x = (x != x.shift())
    x.iloc[0,] = False
    return x

changes = data.groupby(data.index, as_index=False).values.apply(
                       calc_change).reset_index().iloc[:,2]
data = data.sort_index().reset_index()
data.loc[changes, 'change'] = 1 
data = data.fillna(0)

我相信有更好的,感谢任何帮助!

【问题讨论】:

    标签: python pandas dataframe pandas-groupby


    【解决方案1】:

    如果您的 id 列未设置为索引,您可以使用此解决方案。

    data['change'] = data.groupby(['id'])['values'].apply(lambda x: x.diff() > 0).astype(int)
    

    你得到

        id  time             values change
    0   1   2017-01-01 12:00:00 10  0
    1   2   2017-01-01 12:00:00 11  0
    2   3   2017-01-01 12:00:00 12  0
    3   1   2017-01-01 12:10:00 10  0
    4   2   2017-01-01 12:10:00 12  1
    5   3   2017-01-01 12:10:00 13  1
    6   1   2017-01-01 12:20:00 10  0
    7   2   2017-01-01 12:20:00 13  1
    8   3   2017-01-01 12:20:00 13  0
    

    以id为索引,

    data = data.sort_index()
    data['change'] = data.groupby(data.index)['values'].apply(lambda x: x.diff() > 0).astype(int)
    

    【讨论】:

    • 非常感谢。是否也可以将 id 用作索引?
    • 虽然起初它似乎有效,但在我的实际数据集上使用它会导致看似错误的结果。如果我将其与data.groupby('id').values.apply(lambda x: (x != x.shift()).sum() - 1) 进行比较,data['change'] = data.groupby(['id'])['values'].apply(lambda x: x.diff() > 0).astype(int) 的结果与data.groupby('id').change.sum() 的结果会出现强烈分歧。在许多情况下,它大约是一半。任何想法?我有大约 1000 个 ID,数百万行,我的实际值是坐标的纬度(例如 2.12134900 具有不同的长度)
    • 嗯,很抱歉,如果无法重现错误,很难进行猜测工作。
    • 我只是用一个最小的例子来编辑我的答案。因此,我意识到问题所在。仅当差异为正时,您的答案才有效。当连续值低于前一个值时,将不计为变化。这是一个正确的版本:data.groupby('id')['values'].apply(lambda x: abs(x.diff()) > 0).astype(int) 请编辑您的帖子,以便我接受答案:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多