如何替换大于特定阈值的数据帧的每一行中的前n个元素

时间:2016-01-26 13:52:56

标签: python performance pandas dataframe

我有一个只包含数字的巨大数据框(我在下面展示的数据仅用于演示目的)。我的目标是在数据帧的每一行中将大于某个值n的第一个val数字替换为0。

举个例子:

我的数据框可能如下所示:

   c1  c2  c3  c4
0  38  10   1   8
1  44  12  17  46
2  13   6   2   7
3   9  16  13  26

如果我现在选择n = 2(替换次数)和val = 10,我想要的输出将如下所示:

   c1  c2  c3  c4
0   0  10   1   8
1   0   0  17  46
2   0   6   2   7
3   9   0   0  26

在第一行中,只有一个值大于val,因此只有一个值被替换,在第二行中,所有值都大于val,但只能替换前两个值。第3行和第4行的模拟(请注意,不仅前两列受影响,而且行中的前两个值可以在任何列中)。

一个简单而又非常难看的实现可能如下所示:

import numpy as np
import pandas as pd

np.random.seed(1)

col1 = [np.random.randint(1, 50) for ti in xrange(4)]
col2 = [np.random.randint(1, 50) for ti in xrange(4)]
col3 = [np.random.randint(1, 50) for ti in xrange(4)]
col4 = [np.random.randint(1, 50) for ti in xrange(4)]

df = pd.DataFrame({'c1': col1, 'c2': col2, 'c3': col3, 'c4': col4})

val = 10
n = 2

for ind, row in df.iterrows():
    # number of replacements
    re = 0

    for indi, vali in enumerate(row):
        if vali > val:
            df.iloc[ind, indi] = 0
            re += 1
            if re == n:
                break

这有效,但我确信有更有效的方法可以做到这一点。有任何想法吗?

1 个答案:

答案 0 :(得分:2)

您可以自己编写一些奇怪的函数并将applyaxis=1一起使用:

def f(x, n, m):
    y = x.copy()
    y[y[y > m].iloc[:n].index] = 0
    return y

In [380]: df
Out[380]:
   c1  c2  c3  c4
0  38  10   1   8
1  44  12  17  46
2  13   6   2   7
3   9  16  13  26

In [381]: df.apply(f, axis=1, n=2, m=10)
Out[381]:
   c1  c2  c3  c4
0   0  10   1   8
1   0   0  17  46
2   0   6   2   7
3   9   0   0  26

注意y = x.copy()需要制作该系列的副本。如果您需要更改您的值,您可以省略该行。你需要额外的y因为切片你会得到一个副本而不是原始对象。