使用先前的行引用快速循环Python数据帧

I a*_*Nik 8 python loops pandas

假设我有一个包含两列的pandas数据帧:ID和Days.DataFrame在两个变量中按升序排序.例如:

# Initial dataset
data = pd.DataFrame({'id': np.repeat([1, 2 ,3], 4),
                 'day': [1, 2, 10, 11, 3, 4, 12, 15, 1, 20, 21, 24]})

    id  day
0   1   1
1   1   2
2   1   10
3   1   11
4   2   3
5   2   4
6   2   12
7   2   15
8   3   1
9   3   20
10  3   21
11  3   24
Run Code Online (Sandbox Code Playgroud)

我想添加第三列,它会为每个ID*日提供一个"会话"号."会话"是指在一个会话期间之间差异小于2天的一系列天数.例如,序列5,6,7将被视为一个会话,而5,6,9将被视为两个会话,并且应该被标记为0, 0, 1,即第5天和第6天被引用到会话#0,而第9天被引用到会话#1.会话编号应该从0每个新ID开始.

换句话说,我想得到的是:

    id  day session
0   1   1   0
1   1   2   0
2   1   10  1
3   1   11  1
4   2   3   0
5   2   4   0
6   2   12  1
7   2   15  2  
8   3   1   0
9   3   20  1
10  3   21  1
11  3   24  2
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我使用了基本的for循环.在此循环中,我迭代地遍历所有唯一ID,然后从初始数据集中对数据块进行子集化,并为特定ID的每一天分配会话编号.我有这个问题 - 因为初始数据集是数百万行 - 循环需要时间!例如,对于1毫升的线,我的循环花费大约一分钟,这太多了.

如何提高速度?任何方法都很好!如果你知道如何达到预期的结果,例如,一些numpy矩阵操作会减少时间 - 也很好......

我的循环代码:

# Get sessions for every id
sessions = []
for i in data.id.unique():
    id_data = data['day'][data['id']==i].reset_index(drop=True)
    for ind in id_data.index:
        if ind == 0:
            temp = [0]
        elif ((id_data[ind] - id_data[ind - 1]) < 2):
            temp.append(temp[ind - 1])
        else:
            temp.append(temp[ind - 1] + 1)
    sessions.extend(temp)

# Add sessions to the table
data['session'] = sessions 
Run Code Online (Sandbox Code Playgroud)

WeN*_*Ben 8

你可以加上布尔值

data.groupby('id').day.apply(lambda x : x.diff().gt(1).cumsum())
Out[614]: 
0     0
1     0
2     1
3     1
4     0
5     0
6     1
7     2
8     0
9     1
10    1
11    2
Name: day, dtype: int32
Run Code Online (Sandbox Code Playgroud)


cs9*_*s95 5

我们可以利用这样一个事实,即您的数据经过排序以消除fillna,减少两次groupby调用,并消除对数据的需求apply.

df['session'] = df.day.diff().ge(2)
df['session'] = df.groupby('id').session.cumsum()
Run Code Online (Sandbox Code Playgroud)

df
    id  day  session
0    1    1      0.0
1    1    2      0.0
2    1   10      1.0
3    1   11      1.0
4    2    3      0.0
5    2    4      0.0
6    2   12      1.0
7    2   15      2.0
8    3    1      0.0
9    3   20      1.0
10   3   21      1.0
11   3   24      2.0
Run Code Online (Sandbox Code Playgroud)

作为回报,"session"将是一个浮动列.


rah*_*f23 4

您可以使用,和groupby()两次:np.where()diff()cumsum()

data['session'] = np.where(data.groupby('id')['day'].diff().fillna(0)>1, 1, 0)
data['session'] = data.groupby('id')['session'].cumsum()
Run Code Online (Sandbox Code Playgroud)

产量:

    id  day  session
0    1    1        0
1    1    2        0
2    1   10        1
3    1   11        1
4    2    3        0
5    2    4        0
6    2   12        1
7    2   15        2
8    3    1        0
9    3   20        1
10   3   21        1
11   3   24        2
Run Code Online (Sandbox Code Playgroud)