有条件地替换pandas DataFrame中行的值

时间:2016-11-21 19:53:45

标签: python performance pandas

这是我的pandas DataFrame:

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 个答案:

答案 0 :(得分:1)

在groupby操作中使用cumcount:

df.groupby('ID').cumcount()+1

答案 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

答案 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