【问题标题】:Make a Pandas mask based on a column vector根据列向量制作 Pandas 掩码
【发布时间】:2018-04-24 03:23:12
【问题描述】:

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

让我们考虑一下这个数据框:

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 的这两种方法,所以我决定看看哪一种是最快/最佳实现的:

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))

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

  • 220ms 对于mask=(df.T>rowsQuantiles).T
  • 65ms 对于mask=df.apply(lambda row: row > rowsQuantiles)
  • 21msdf.gt(rowsQuantiles,0),接受的答案。

【问题讨论】:

  • 没有机会,这些都是垃圾时间。请参阅我的回答,我已使用您的数据通过 timeit 正确计时。
  • 我在你的回答中看到的都是我发布的内容,对吧?
  • 您声称您接受的答案是最快的。我说不是。更重要的是,无论出于何种原因,您都对非常好的答案投了反对票。
  • 没有注意到gt 的方法,现在已经更正了,抱歉。除此之外,àpply 比双转置更快,这就是我的意思是你的帖子与我的一致的原因。不过不会和你玩争论/投反对票的游戏
  • 没问题,退回反对票并继续前进要容易得多:)

标签: python pandas filter slice mask


【解决方案1】:

你的掩码有一个转置错误,但假设你想用 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

【讨论】:

  • 是的,我知道显而易见的解决方案就是这么简单,但这次有点慢。
  • @cᴏʟᴅsᴘᴇᴇᴅ 我有点惊讶df > rowsQuantiles 不只是工作!
【解决方案2】:
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

【讨论】:

  • 谢谢!但看起来 Wen 的回答要快得多 - 请参阅 cᴏʟᴅsᴘᴇᴇᴅ 回答中的时间部分。
【解决方案3】:

我可以落后的另一种选择是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)

它返回一个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

【讨论】:

    【解决方案4】:

    也只能使用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
    

    【讨论】:

    • 有趣的解决方案!
    • 这很整洁
    • @cᴏʟᴅsᴘᴇᴇᴅ 很好,我们不能期待更多。;-)
    • 抱歉,打错了,我的错
    • @ylnor 你有胆量在没有测试的情况下拒绝其他答案......非常令人失望
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 1970-01-01
    • 2017-11-10
    • 1970-01-01
    • 2017-03-18
    • 2017-01-09
    相关资源
    最近更新 更多