Python 在pandas中更快地替代Series.add功能
我想把两只熊猫系列加在一起。第一个系列非常大,有一个多索引。第二个系列的索引是第一个系列索引的一个小子集Python 在pandas中更快地替代Series.add功能,python,pandas,Python,Pandas,我想把两只熊猫系列加在一起。第一个系列非常大,有一个多索引。第二个系列的索引是第一个系列索引的一个小子集 df1 = pd.DataFrame(np.ones((1000,5000)),dtype=int).stack() df1 = pd.DataFrame(df1, columns = ['total']) df2 = pd.concat([df1.iloc[50:55],df1.iloc[2000:2005]]) # df2 is tiny subset of d
df1 = pd.DataFrame(np.ones((1000,5000)),dtype=int).stack()
df1 = pd.DataFrame(df1, columns = ['total'])
df2 = pd.concat([df1.iloc[50:55],df1.iloc[2000:2005]]) # df2 is tiny subset of df1
第一次使用常规Series.add函数大约需要9秒,后续尝试需要2秒(可能是因为pandas优化了df在内存中的存储方式?)
第一次手动迭代行的长度约为Series.add的2/3,后续尝试时的长度约为Series.add的1/100
starttime = time.time()
result = df1.total.copy()
for row_index, row in df2.iterrows():
result[row_index] += row
print "Method 2 took %f seconds" % (time.time() - starttime)
当(此处)索引为多索引时,速度差异尤其明显
为什么Series.add在这里不起作用?有没有加快这一进程的建议?除了迭代序列中的每个元素,还有更有效的替代方法吗
另外,如何对数据帧进行排序或构造,以提高这两种方法的性能?第二次运行这两种方法中的任何一种都要快得多。我怎样才能在第一次演出时获得这样的表演?使用sort_索引进行排序的帮助不大 我认为在这种特定情况下,您的第二个可能会更快,因为您正在迭代较小的数据集(工作量较小),然后只访问较大数据集的少数组件(多亏了pandas开发人员,这是一个高效的操作) 然而,使用
.add
方法,pandas必须查看这两个索引的整体
如果
df1
和df2
长度相同,则第一种方法需要54毫秒,但第二种方法需要>2分钟(在我的机器上,显然是YMMV)。您不需要循环:
df1.total[df2.index] += df2.total
In [11]: %%timeit
result = df1.total.copy()
for row_index, row in df2.iterrows():
result[row_index] += row
100 loops, best of 3: 17.9 ms per loop
In [12]: %timeit df1.total[df2.index] = (df1.total[df2.index]).add(df2.total, fill_value=0)
1000 loops, best of 3: 325 µs per loop
In [13]: %timeit df1.total[df2.index] += df2.total
1000 loops, best of 3: 283 µs per loop
HYRY回答说,在这种情况下,更有效的方法是只查看df2索引的一小部分。您可以使用稍微更健壮的函数(可以填充NAN)来实现这一点: 虽然这里的语法不是很枯燥 通过比较一些timeit信息,我们可以看到add并没有显著降低速度,两者都是对您的naive for循环的巨大改进:
df1.total[df2.index] += df2.total
In [11]: %%timeit
result = df1.total.copy()
for row_index, row in df2.iterrows():
result[row_index] += row
100 loops, best of 3: 17.9 ms per loop
In [12]: %timeit df1.total[df2.index] = (df1.total[df2.index]).add(df2.total, fill_value=0)
1000 loops, best of 3: 325 µs per loop
In [13]: %timeit df1.total[df2.index] += df2.total
1000 loops, best of 3: 283 µs per loop
这是一个有趣的问题(我可能会在后面补充)什么样的相对尺寸会更快,但在这种极端情况下肯定会有一个巨大的胜利
要从中吸取的东西是:
如果您正在编写一个for循环(用python)来加快速度,那么您就错了!:) 第二次更快的原因是在需要时计算索引哈希表,然后缓存(这就是快速查找元素的原因)。您在这里所做的是将一个小得多的系列重新索引为一个大的系列,这就是为什么它需要时间,但不是必需的@下面的HYRY解决方案就是解决方法。明白了!谢谢HYRY和Andy的详细解释。谢谢!循环仍然胜过天真的np.add,但仅仅添加一个片段就可以轻而易举地击败这两个角色。