Pandas DataFrame中行的值的条件替换

3

这是我的Pandas数据帧:

ID  START   END  SEQ
1   11      12   5
1   14      15   6 
1   13      14   7 
2   10      14   1
3   11      15   1
3   16      17   2

我希望更改SEQ的值,使得相同ID的SEQ值为1、2等,例如:

ID  START   END  SEQ
1   11      12   1
1   14      15   3 
1   13      14   2 
2   10      14   1
3   11      15   1
3   16      17   2

如何在避免使用循环的情况下高效地完成它?
3个回答

1
在分组操作中使用cumcount:
df.groupby('ID').cumcount()+1

0

在 Boud 的回答中加入一点内容,如果您的意图是使得结果 SEQ 列中的顺序取决于 START 列的值,您可以通过以下方式实现

df['SEQ'] = df.sort_values(by='START').groupby('ID').cumcount()+1

也就是说,

In [3]: df
Out[3]: 
   ID  START  END  SEQ
0   1     11   12    5
1   1     14   15    6
2   1     13   14    7
3   2     10   14    1
4   3     11   15    1
5   3     16   17    2

In [4]: df['SEQ'] = df.sort_values(by='START').groupby('ID').cumcount()+1

In [5]: df
Out[5]: 
   ID  START  END  SEQ
0   1     11   12    1
1   1     14   15    3
2   1     13   14    2
3   2     10   14    1
4   3     11   15    1
5   3     16   17    2

0

这里有两种使用 NumPy 的方法,使用 np.cumsum 来创建这些ramp数组 -

def id_ramp(a):
    out = np.ones(a.size,dtype=int)
    idx = np.nonzero(np.append(True,a[1:] > a[:-1]))[0]
    out[idx[1:]] = -idx[1:] + idx[:-1] + 1
    return out.cumsum()

def id_ramp2(a):
    out = np.ones(a.size,dtype=int)
    idx = np.nonzero(a[1:] > a[:-1])[0]+1
    out[idx[0]] = -idx[0]+1
    out[idx[1:]] = idx[:-1] - idx[1:]+1
    return out.cumsum()

运行时测试 -

In [381]: a = np.sort(np.random.randint(1,100,(1000)))

In [382]: df = pd.DataFrame(a, columns=[['ID']])

In [383]: %timeit df['SEQ'] = df.groupby('ID').cumcount()+1 #@Boud's soln
100 loops, best of 3: 2.01 ms per loop

In [384]: %timeit df['SEQ'] = id_ramp(df.ID.values)
1000 loops, best of 3: 315 µs per loop

In [385]: %timeit df['SEQ'] = id_ramp2(df.ID.values)
1000 loops, best of 3: 304 µs per loop

如果您正在使用未始终排序的ID列,则需要在那里使用一些argsort,如下所示 -

a = df.ID.values
sidx = a.argsort(kind='mergesort')
df['SEQ'] = id_ramp2(a[sidx])[sidx.argsort()]

让我们看一个示例来了解它的工作原理 -

In [447]: df
Out[447]: 
    ID
0    1
1    1
2    7
3    5
4    3
5    8
6    1
7    3
8    7
9    2
10   5
11   7

In [448]: a = df.ID.values
     ...: sidx = a.argsort(kind='mergesort')
     ...: df['SEQ'] = id_ramp2(a[sidx])[sidx.argsort()]
     ...: 

In [449]: df
Out[449]: 
    ID  SEQ
0    1    1
1    1    2
2    7    1
3    5    1
4    3    1
5    8    1
6    1    3
7    3    2
8    7    2
9    2    1
10   5    2
11   7    3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接