基于布尔值列表返回子集

时间:2017-08-03 21:16:37

标签: python pandas dataframe

我试图根据值列表对数据帧进行切片,我该怎么做?

假设我有一个列表l,它看起来像:[0,1,0,0,1,1,0,0,0,1]

我希望返回数据框中的所有行,df,基于列表中的值是否为1.在此示例中,我将包括index为1,4,5和9的行。任何简单的方法去做这个?请道歉,如果这是一个简单的问题,但我仍然习惯于数据帧。

6 个答案:

答案 0 :(得分:17)

您可以在此处使用遮罩:

df[np.array([0,1,0,0,1,1,0,0,0,1],dtype=bool)]

因此我们构造一个带有true和false的布尔数组。数组为True的每个位置都是我们选择的行。

请注意我们过滤到位。为了检索结果,您必须将结果分配给(可选地不同的)变量:

df2 = df[np.array([0,1,0,0,1,1,0,0,0,1],dtype=bool)]

答案 1 :(得分:13)

将列表转换为布尔数组,然后使用布尔索引:

df = pd.DataFrame(np.random.randint(10, size=(10, 3)))

df[np.array(lst).astype(bool)]
Out: 
   0  1  2
1  8  6  3
4  2  7  3
5  7  2  3
9  1  3  4

答案 2 :(得分:11)

<强>设置
借用了@ ayhan的设置

df = pd.DataFrame(np.random.randint(10, size=(10, 3)))

没有numpy
不是最快的,但它拥有自己的,绝对是最短的。

df[list(map(bool, lst))]

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

计时

results.div(results.min(1), 0).round(2).pipe(lambda d: d.assign(Best=d.idxmin(1)))

         ayh   wvo   pir   mxu   wen Best
N                                        
1       1.53  1.00  1.02  4.95  2.61  wvo
3       1.06  1.00  1.04  5.46  2.84  wvo
10      1.00  1.00  1.00  4.30  2.73  ayh
30      1.00  1.05  1.24  4.06  3.76  ayh
100     1.16  1.00  1.19  3.90  3.53  wvo
300     1.29  1.00  1.32  2.50  2.38  wvo
1000    1.54  1.00  2.19  2.24  3.85  wvo
3000    1.39  1.00  2.17  1.81  4.55  wvo
10000   1.22  1.00  2.21  1.35  4.36  wvo
30000   1.19  1.00  2.26  1.39  5.36  wvo
100000  1.19  1.00  2.19  1.31  4.82  wvo
fig, (a1, a2) = plt.subplots(2, 1, figsize=(6, 6))
results.plot(loglog=True, lw=3, ax=a1)
results.div(results.min(1), 0).round(2).plot.bar(logy=True, ax=a2)
fig.tight_layout()

enter image description here

测试代码

ayh = lambda d, l: d[np.array(l).astype(bool)]
wvo = lambda d, l: d[np.array(l, dtype=bool)]
pir = lambda d, l: d[list(map(bool, l))]
wen = lambda d, l: d.loc[[i for i, x in enumerate(l) if x == 1], :]

def mxu(d, l):
    a = np.array(l)
    return d.query('@a != 0')

results = pd.DataFrame(
    index=pd.Index([1, 3, 10, 30, 100, 300,
                    1000, 3000, 10000, 30000, 100000], name='N'),
    columns='ayh wvo pir mxu wen'.split(),
    dtype=float
)

for i in results.index:
    d = pd.concat([df] * i, ignore_index=True)
    l = lst * i
    for j in results.columns:
        stmt = '{}(d, l)'.format(j)
        setp = 'from __main__ import d, l, {}'.format(j)
        results.set_value(i, j, timeit(stmt, setp, number=10))

答案 3 :(得分:7)

另一个&#34;创意&#34;的方法:

In [181]: a = np.array(lst)

In [182]: df.query("index * @a > 0")
Out[182]:
   0  1  2
1  1  5  5
4  0  2  0
5  4  9  9
9  2  2  5

much better variant from @ayhan

In [183]: df.query("@a != 0")
Out[183]:
   0  1  2
1  1  5  5
4  0  2  0
5  4  9  9
9  2  2  5

PS我还借用了@Ayhan的设置

答案 4 :(得分:4)

或者可能会在list中找到1的位置并从Dataframe

切片
df.loc[[i for i,x in enumerate(lst) if x == 1],:]

答案 5 :(得分:1)

选择使用布尔列表是itertools.compress做得很好的事。

鉴于

>>> df = pd.DataFrame(np.random.randint(10, size=(10, 2)))
>>> selectors = [0, 1, 0, 0, 1, 1, 0, 0, 0, 1]

代码

>>> selected_idxs = list(itertools.compress(df.index, selectors))   # [1, 4, 5, 9]
>>> df.iloc[selected_idxs, :]
   0  1
1  1  9
4  3  4
5  4  1
9  8  9