Pandas:通过创建索引来加速过滤?
我想在一个网页应用中像用SQL那样使用pandas(因为数据量不到1GB,而且不经常变化,所以不想用pSQL来存储数据,只想用pandas的DataFrame来存)。如果我想根据多个条件来查找数据,比如说年龄大于x、年龄小于y、收入大于p、收入小于q,有没有什么方法可以加快这个过滤的速度?或者说下面的内容已经解决了这个问题。在SQL中,我们会为年龄和收入建立索引来加速查询,我想知道在pandas中有没有类似的方法。
3 个回答
当处理一个超过四千万行的数据表(dfBig)时,使用布尔索引(在循环中)变得非常慢。
这里有一些伪代码对我有用;基本上是把 dfBig 用 df.groupby() 分成一个字典,然后用字典里的内容来代替直接索引:
# very slow version:
colValues = dfBig.SomeField1.unique()
indValues = dfBig.SomeField2.unique()
dfResult = ... # set up output dataframe
for col in colValues:
for idx in indValues:
boolIndex = (dfBig.SomeField1 == col) & (dfBig.SomeField2 == idx)
fetchValue = dfBig[boolIndex] # this takes a looong time
dfResult.loc[idx, col] = someFuncion(fetchValue)
# much faster version:
dicCol = {x:y for x,y in df.groupby(SomeField1)}
for col,dfCol in dicCol.items():
dfIdx = {x:y for x,y in dfCol.groupby(SomeField2)}
for idx, dfIdx in dicIdx.items():
dfResult.oc[idx, col] = someFunction(dfIdx)
这个“更快的版本”让处理这个四千万行的数据表速度提升了大约一百倍。
Pandas其实就是一个围绕着numpy.ndarray
的包装工具。
所有的搜索操作实际上都是在用ndarray
内部进行的。
df[(df.age > x) & (y < df.age) & (df.income > p) & (df.income < q)]
这样做应该没问题。不过,你可以通过直接使用numpy.ndarray
或者使用掩码数组来加快这个过程:http://docs.scipy.org/doc/numpy/reference/maskedarray.html
这样做不会为你新生成的数组分配新的内存。这意味着你不需要花时间和CPU去寻找和分配新的内存来存放你的“过滤”结果,也不会因为复制本身而增加内存的使用。(其实这并不完全正确,因为掩码还是需要存储在某个地方,但你仍然不需要把你的表格值复制到内存的其他地方)
不过,这样做也有代价:使用掩码数组时,处理起来会稍微慢一些,因为系统需要检查内存中的每个值是否被掩码。不过,如果只是用来“过滤”,这种额外的访问时间应该是感觉不到的(当你想用掩码数组进行计算时,这个问题就变得很重要了)。
编辑:
为了在磁盘和内存中实现持久和优化的数据访问,可以使用PyTables,它是为此优化的。不过,Pytables以及Numpy/Pandas并不是为了这样使用而设计的。
用“pandas”的方式来做这个查询是:
df[(x < df.age) & (df.age < y) & (p < df.income) & (df.income < q)]
pandas 默认会对所有东西进行索引,包括所有的列,所以你不需要提前明确声明你要查询的内容。
(我不能确定这种设置对你的数据集是否合适。)