在复杂条件下消除Pandas数据帧中的行

时间:2015-07-06 04:22:04

标签: python-3.x numpy pandas

我有一个带有一些列和221行的Pandas DataFrame。让我们说感兴趣的列是'col1''col2''col1'包含所有字符串,而'col2'都是整数。现在我想要消除'col1' == 'A' & 'col2' == 1

中的行

很容易得到一个布尔向量,True对应于满足条件的所有行。为了删除它们,我想如果我可以反转布尔向量(满足条件的False),我可以用倒置向量索引我的DataFrame并完成。

在我的过程中,我认为发现了一个有趣的发现:列表理解比布尔向量的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

无论如何,我得到了我想要的东西。但是,有更快的方法吗?我将不得不在不久的将来在更大的DataFrame上运行它。谢谢你的帮助!

1 个答案:

答案 0 :(得分:3)

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

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

Timing results

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