Python 3.x 在复杂条件下消除数据帧中的行

Python 3.x 在复杂条件下消除数据帧中的行,python-3.x,numpy,pandas,Python 3.x,Numpy,Pandas,我有一个包含一些列和221行的数据框架。假设感兴趣的列是'col1'和'col2''col1'包含所有字符串,而'col2'包含所有整数。现在我想消除'col1'='A'&'col2'==1的行 很容易得到与满足条件的所有行相对应的True布尔向量。为了删除它们,我想如果我可以反转布尔向量(haveFalse在满足条件的地方),我就可以用反转的向量索引我的数据帧并完成 在这个过程中,我有一个有趣的发现:对于布尔向量,列表理解比numpy反转方法要快。这个向量的长度是221。以下是我所做的: In

我有一个包含一些列和221行的数据框架。假设感兴趣的列是
'col1'
'col2'
'col1'
包含所有字符串,而
'col2'
包含所有整数。现在我想消除
'col1'='A'&'col2'==1
的行

很容易得到与满足条件的所有行相对应的
True
布尔向量。为了删除它们,我想如果我可以反转布尔向量(have
False
在满足条件的地方),我就可以用反转的向量索引我的数据帧并完成

在这个过程中,我有一个有趣的发现:对于布尔向量,列表理解比numpy反转方法要快。这个向量的长度是221。以下是我所做的:

In  [1]: def npinvert():
             return np.invert((df['col1'] == 'A') & (df['col2'] == 1))
         def licomp():
             return [not i for i in ((df['col1'] == 'A') & (df['col2'] == 1))]
然后:

In  [2]: %timeit npinvert()
Out [2]: 1000 loops, best of 3: 902 µs per loop

In  [3]: %timeit licomp()
Out [3]: 1000 loops, best of 3: 880 µs per loop

无论如何,我得到了我想要的。但是,有没有更快的方法可以做到这一点?在不久的将来,我将不得不在一个更大的数据帧上运行它。谢谢你的帮助

要真正比较这些,您需要在各种尺寸上测试它们。添加您可以想到的任何测试函数,看看您是否可以改进pandas方法的
~(conditions)

一旦数据帧变得相当大,使用矢量化
pandas
~和
numpy.invert
来反转布尔值似乎要快得多。

此外,列表理解生成一个列表(duh),其他的返回一个数组或序列。假设需要一个系列,那么将列表转换为系列只需要额外的一小部分时间。但从更大的角度来看,这些布尔运算并不是真正的矢量化数学运算,所以我认为我们不希望看到比使用列表理解向列表的每个元素添加9比在numpy中执行相同的操作(这基本上是结果显示的)要快多少。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Big (100,000 rows) test dataset
df = pd.DataFrame({'a': np.random.randint(1, 10, 100000),
                   'b': [np.random.choice(['A', 'B', 'C']) for i in range(100000)]})

def check_pandas(df):
    return ~ ((df['a'] == 1) & (df['b'] == 'A'))

def check_list(df):
    return [not i for i in ((df['b'] == 'A') & (df['a'] == 1))]

def check_numpy(df):
   return np.invert((df['a'] == 1) & (df['b'] == 'A'))

sizes = []
pandas_times = []
list_times = []
np_times = []

for df_size in range(1, 100001, 1000):
    sizes.append(df_size)

    current_df = df.iloc[:df_size, :]
    pandas_before = time.time()
    check_pandas(current_df)
    pandas_after = time.time()
    pandas_times.append(float(pandas_after - pandas_before))

    before = time.time()
    check_list(current_df)
    after = time.time()
    list_times.append(float(after - before))

    before = time.time()
    check_numpy(current_df)
    after = time.time()
    np_times.append(float(after - before))


# Plot results
fig, ax = plt.subplots()
ax.plot(sizes, pandas_times, 'ro', label='pandas')
ax.plot(sizes, list_times, 'bs', label='list')
ax.plot(sizes, np_times, 'g+', label='numpy')
ax.legend(loc='upper left')