高效的查询pandas数据集

时间:2016-06-28 15:06:29

标签: python pandas dataframe

鉴于pandas数据集包含800万行和20列。

程序查询数据集以查找某个列的平均值。

基于其他列选择的平均值

需要帮助以获得对10k查询捆绑的快速响应并缩短查询执行时间

设置:

import pandas as pd
from random import randint


df = pd.DataFrame({'A': ['A1','A2','A3','A4','A5','A2','A2','A1','A4','A4'],
               'B': ['BA1','BA2','BA3','BA4','BA5','BA2','BA2','BA1','BA4','BA4'],
               'C': ['CA1','CA2','CA3','CA4','CA5','CA2','CA2','CA1','CA4','CA4'],
               'D': ['D1','D2','D3','D4','D5','D2','D2','D1','D4','D4'],
               'important_col': [randint(1, 9)*100 for x in xrange(10)]})

数据集示例:

        A    B       C      D   important_col
  0     A1  BA1     CA1     D1  400
  1     A2  BA2     CA2     D2  500
  2     A3  BA3     CA3     D3  100
  3     A4  BA4     CA4     D4  100
  4     A5  BA5     CA5     D5  400
  5     A2  BA2     CA2     D2  900
  6     A2  BA2     CA2     D2  100
  7     A1  BA1     CA1     D1  300
  8     A4  BA4     CA4     D4  800
  9     A4  BA4     CA4     D4  100

查询示例:

df[(df['A']== 'A1')]['important_col'].mean()
df[(df['A']== 'A2') & (df['B'] == 'BA2')]['important_col'].mean()
df[(df['A']== 'A4') & (df['C'] == 'CA4') & (df['D'] == 'D4')]['important_col'].mean()

索引是否有助于解决问题?可以使用.loc.ix吗?或任何其他解决方案?

2 个答案:

答案 0 :(得分:3)

A至D列可以转换为类别,因为这些值是非唯一且有限的。

以下示例基于您在OP中提供的df。

# Original data frame
df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 5 columns):
A                10 non-null object
B                10 non-null object
C                10 non-null object
D                10 non-null object
important_col    10 non-null int64
dtypes: int64(1), object(4)
memory usage: 480.0+ bytes

# Convert to category
df['A'] = df.A.astype('category')
df['B'] = df.B.astype('category')
df['C'] = df.C.astype('category')
df['D'] = df.D.astype('category')

# Modified data frame
df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 5 columns):
A                10 non-null category
B                10 non-null category
C                10 non-null category
D                10 non-null category
important_col    10 non-null int64
dtypes: category(4), int64(1)
memory usage: 360.0 bytes

您应该看到内存使用的好处(值被整数替换并使用小型查找表映射)以及选择时的速度(基于整数值的查找将比使用字符串值的相同查找更快)

更新

我创建了一个Jupyter notebook来显示简单地将列转换为类别的改进。

使用1.000.000行的样本(与OP定义的结构相同)和OP中提供的示例查询,有一个内存使用改进,因为大小从232.7 MB下降到11.4 MB(减少95%)。

此外,示例查询还显示速度效益

  • 查询1:83%的改进(57毫秒> 9.36毫秒)
  • 查询2:91%的改进(80.9毫秒> 6.97毫秒)
  • 查询3:92%的改进(119毫秒> 9.37)

我使用8 mio样本进行了相同的测试,从而提高了速度和资源使用量。

答案 1 :(得分:2)

@Kristof的答案是一个很好的开始。我注意到这个建议加速了不到2倍。对于大型DataFrame,要记住的一些其他事项是使用的表达式的顺序(例如,您是否需要创建新的DataFrame来选择系列,或者您是否可以直接生成新的Series)。当不需要丰富的Pandas方法时,也可以直接使用numpy类型。

扩展您的示例:

In [58]: df_big = pd.DataFrame()
In [59]: for i in range(1000): df_big = df_big.append(df)
In [61]: len(df_big)
Out[61]: 10000

In [62]: dfr = df_big.to_records()

In [63]: dfr
Out[63]: 
rec.array([(0, 'A1', 'BA1', 'CA1', 'D1', 900), (1, 'A2', 'BA2', 'CA2', 'D2', 900),
 (2, 'A3', 'BA3', 'CA3', 'D3', 500), ...,
 (7, 'A1', 'BA1', 'CA1', 'D1', 700), (8, 'A4', 'BA4', 'CA4', 'D4', 300),
 (9, 'A4', 'BA4', 'CA4', 'D4', 500)], 
          dtype=[('index', '<i8'), ('A', '|O'), ('B', '|O'), ('C', '|O'), ('D', '|O'), ('important_col', '<i8')])


In [71]: %timeit df_big[(df_big['A']== 'A4') & (df_big['C'] == 'CA4') & (df_big['D'] == 'D4')]['important_col'].mean() 
100 loops, best of 3: 2.91 ms per loop

In [72]: %timeit df_big['important_col'][(df_big['A']== 'A4') & (df_big['C'] == 'CA4') & (df_big['D'] == 'D4')].mean()
100 loops, best of 3: 2.46 ms per loop

In [73]: df_big[(df_big['A']== 'A4') & (df_big['C'] == 'CA4') & (df_big['D'] == 'D4')]['important_col'].mean()

In [74]: %timeit dfr['important_col'][(dfr['A']== 'A4') & (dfr['C'] == 'CA4') & (dfr['D'] == 'D4')].mean()
1000 loops, best of 3: 877 µs per loop