根据列向量制作 Pandas 掩码

Make a Pandas mask based on a column vector

我有一个给定的数据框,我希望每一行都能够 select 高于该行给定百分位数的值。

让我们考虑这个数据框:

df = pd.DataFrame({'A' : [5,6,3,4, 0,5,9], 'B' : [1,2,3, 5,7,0,1]})

   A  B
0  5  1
1  6  2
2  3  3
3  4  5
4  0  7
5  5  0
6  9  1

每行第 20 个分位数的给定向量:

rowsQuantiles = df.quantile(0.2, axis=1)

0    1.8
1    2.8
2    3.0
3    4.2
4    1.4
5    1.0
6    2.6

我希望能够为每一行过滤掉低于该行分位数的值,以获得以下结果:

quantileMask = df > rowsQuantiles

   A      B
0  True   False
1  True   False
2  False  False
3  False  True  
4  False  True  
5  True   False
6  True   False

编辑:

我真的很喜欢@andrew_reece 和@Andy Hayden 的两种方法,所以我决定看看哪一种是 fastet/best-implemented:

N=10000000
df = pd.DataFrame({'A' : [random.random() for i in range(N)], 'B' : [random.random() for i in range(N)]})
rowsQuantiles = df.quantile(0.2, axis=1)

t0=time.time()

mask=(df.T>rowsQuantiles).T
#mask=df.apply(lambda row: row > rowsQuantiles)

print(str(time.time()-t0))

结果非常简单(经过多次重复测试):

你的掩码存在转置错误,但假设你想用 NaN 替换值,你正在寻找的方法是 where:

In [11]: df.T > rowsQuantiles
Out[11]:
       0      1      2      3      4      5      6
A   True   True  False  False  False   True   True
B  False  False  False   True   True  False  False

In [12]: (df.T > rowsQuantiles).T
Out[12]:
       A      B
0   True  False
1   True  False
2  False  False
3  False   True
4  False   True
5   True  False
6   True  False

In [13]: df.where((df.T > rowsQuantiles).T)
Out[13]:
     A    B
0  5.0  NaN
1  6.0  NaN
2  NaN  NaN
3  NaN  5.0
4  NaN  7.0
5  5.0  NaN
6  9.0  NaN
df.apply(lambda row: row > rowsQuantiles)

       A      B
0   True  False
1   True  False
2  False  False
3  False   True
4  False   True
5   True  False
6   True  False

我可以支持的另一种选择是 np.where:

np.where(df.values > rowsQuantiles[:, None], True, False)

array([[ True, False],
       [ True, False],
       [False, False],
       [False,  True],
       [False,  True],
       [ True, False],
       [ True, False]], dtype=bool)

哪个 returns 一个 numpy 数组,如果你同意的话。


时间

%timeit df.T > rowsQuantiles
1 loop, best of 3: 251 ms per loop

%timeit df.where((df.T > rowsQuantiles).T)
1 loop, best of 3: 583 ms per loop

%timeit np.where(df.values > rowsQuantiles[:, None], True, False)
10 loops, best of 3: 136 ms per loop

%timeit df.add(-rowsQuantiles,0).gt(0)
10 loops, best of 3: 141 ms per loop

%timeit df.gt(rowsQuantiles,0)
10 loops, best of 3: 25.4 ms per loop

%timeit df.apply(lambda row: row > rowsQuantiles)
10 loops, best of 3: 60.6 ms per loop

也只使用gt

df.gt(rowsQuantiles,0)
Out[288]: 
       A      B
0   True  False
1   True  False
2  False  False
3  False   True
4  False   True
5   True  False
6   True  False

使用add

df.add(-rowsQuantiles,0).gt(0)
Out[284]: 
       A      B
0   True  False
1   True  False
2  False  False
3  False   True
4  False   True
5   True  False
6   True  False