创建前n个值的数据框架的更有效方法 - python

时间:2017-06-08 10:51:08

标签: python pandas numpy dataframe

我有一个类别的数据框,我需要通过将值限制在前n个类别来清理。任何不在前n个类别中的值应该在0(或“其他”)下分箱。

我尝试了下面的代码,它循环遍历列的每一行,然后遍历数据框中的每一列,以检查该列的前n个value_counts中是否找到该位置的值。如果是,则保留该值,如果不是,则替换为0.

此实现在技术上有效,但是当行数很大时,运行时间太长。在pandas / numpy中实现这个目标的最快方法是什么?

z = pd.DataFrame(np.random.randint(1,4,size=(100000, 4)))
x=pd.DataFrame()    
n=10
for j in z:
    for i in z[j].index:     
        if z.at[i,j] in z[j].value_counts().head(n).index.tolist():
            x.at[i,j] = z.at[i,j]
        else:
            x.at[i,j]= 0
print(x) 

1 个答案:

答案 0 :(得分:1)

我认为您可以将apply用于自定义函数的循环列,其中value_counts用于最高值,whereisin用于替换布局掩码:

def f(x):
    y = x.value_counts().head(n).index
    return x.where(x.isin(y), 0)

print (z.apply(f))

与...相同:

print (z.apply(lambda x: x.where(x.isin(x.value_counts().head(n).index), 0)))

样品:

#N =100000
N = 10
np.random.seed(123)
z = pd.DataFrame(np.random.randint(1,4,size=(N, 4)))
print (z)
   0  1  2  3
0  3  2  3  3
1  1  3  3  2
2  3  2  3  2
3  1  2  3  2
4  1  3  1  2
5  3  2  1  1
6  1  1  2  3
7  1  3  1  1
8  2  1  2  1
9  1  1  3  2
x=pd.DataFrame()    
n=2
for j in z:
    for i in z[j].index:     
        if z.at[i,j] in z[j].value_counts().head(n).index.tolist():
            x.at[i,j] = z.at[i,j]
        else:
            x.at[i,j]= 0
print(x) 
     0    1    2    3
0  3.0  2.0  3.0  0.0
1  1.0  3.0  3.0  2.0
2  3.0  2.0  3.0  2.0
3  1.0  2.0  3.0  2.0
4  1.0  3.0  1.0  2.0
5  3.0  2.0  1.0  1.0
6  1.0  0.0  0.0  0.0
7  1.0  3.0  1.0  1.0
8  0.0  0.0  0.0  1.0
9  1.0  0.0  3.0  2.0
print (z.apply(lambda x: x.where(x.isin(x.value_counts().head(n).index), 0)))
   0  1  2  3
0  3  2  3  0
1  1  3  3  2
2  3  2  3  2
3  1  2  3  2
4  1  3  1  2
5  3  2  1  1
6  1  0  0  0
7  1  3  1  1
8  0  0  0  1
9  1  0  3  2

numpy.where类似的解决方案:

print (z.apply(lambda x: np.where(x.isin(x.value_counts().head(n).index), x, 0)))
   0  1  2  3
0  3  2  3  0
1  1  3  3  2
2  3  2  3  2
3  1  2  3  2
4  1  3  1  2
5  3  2  1  1
6  1  0  0  0
7  1  3  1  1
8  0  0  0  1
9  1  0  3  2