在熊猫中合并的速度如何?即使我还没有对索引进行排序?

Jef*_*own 5 performance merge pandas

我正在熊猫中合并两个数据集,并希望加快处理速度,因此我将两个数据集都放在了用于合并的列上。(以前这些列根本没有排序。)排序不会引起明显的速度差异。两者都花了大约八秒钟。

如果我是根据两页纸的页码进行手动合并的,那么我将首先按页码对它们进行排序。否则,我将不得不在堆栈之间进行很多来回切换。

我编写了一个测试以比较这两个过程。它生成两个帧,每个帧随机排列一百万行。然后,它会生成另外两个已在第一列上排序的文件。然后合并前两个,最后合并后两个。

数据生成过程是如此缓慢,以至于我没有时间尝试更多的行-但是尽管如此,合并还是在零可感知时间内发生,即使没有排序也是如此。

import pandas as pd
import numpy as np

def shuffle(df, n=1, axis=0):
  """ /sf/ask/1104040661/ """
  df = df.copy()
  for _ in range(n):
    df.apply(np.random.shuffle, axis=axis)
  return df

# Create some shuffled data
df1 = pd.DataFrame({'A':range(1000000), 'B':range(1000000)})
df2 = pd.DataFrame({'A':range(1000000), 'B':range(1000000)})
df1 = shuffle(df1)
df2 = shuffle(df2)

# Sort that data on column A
df1s = df1.sort_values(by='A')
df2s = df2.sort_values(by='A')

m  = df1. merge(df2,  on='A') # Merge the unsorted data
ms = df1s.merge(df2s, on='A') # Merge the sorted data
Run Code Online (Sandbox Code Playgroud)

编辑:我写了一个数据是宽50倍和高1/5的数据的测试,现在排序似乎有所帮助?

import pandas as pd
import numpy as np

def shuffle(df, n=1, axis=0):
  """ /sf/ask/1104040661/ """
  df = df.copy()
  for _ in range(n):
    df.apply(np.random.shuffle, axis=axis)
  return df

# Create some shuffled data
nrows = 200000
reorderedIntegers  = shuffle( pd.DataFrame({ 'A':range(nrows) }) )
reorderedIntegers2 = shuffle( pd.DataFrame({ 'A':range(nrows) }) )

# Widen it
extraColumns = pd.DataFrame( np.random.rand( nrows, 100 ) )
df  = pd.concat( [reorderedIntegers,  extraColumns], axis=1 )
df2 = pd.concat( [reorderedIntegers2, extraColumns], axis=1 )

# Create sorted copies
dfs  = df .sort_values(by='A')
dfs2 = df2.sort_values(by='A')

# Compare merge speeds
m  = df. merge(df2,  on='A') # Merge the unsorted data
ms = dfs.merge(df2s, on='A') # Merge the sorted data -- substantially faster now
Run Code Online (Sandbox Code Playgroud)

PS我想使用timeit.timeit()来测量两个例程的速度,但是我不断收到如下错误:

>>> timeit.timeit( "ms = df1s.merge(df2s, on='A')" )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/conda/lib/python3.6/timeit.py", line 233, in timeit
    return Timer(stmt, setup, timer, globals).timeit(number)
  File "/opt/conda/lib/python3.6/timeit.py", line 178, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 6, in inner
NameError: name 'df1s' is not defined
Run Code Online (Sandbox Code Playgroud)

Eli*_*ott 5

对于初学者来说,pandas DataFrame 并不是作为简单的多维数组实现的。在代码中,它将对象描述为:

带有标记轴(行和列)的二维大小可变、可能异构的表格数据结构。算术运算在行标签和列标签上对齐。可以被认为是 Series 对象的类似字典的容器。

这是相当复杂的,我不希望有人立即理解它。

这里提到的是,它“可以被认为”是一个类似字典的对象。这意味着它可能使用某种哈希映射,这意味着恒定的查找时间。

合并哈希映射与合并数组(合并两叠论文所做的事情)是不可比的,因为后端结构完全不同。因此排序不会产生任何影响。

不幸的是,DataFrame 和哈希图之间的连接并不完美。哈希映射通常是未排序的,并且不能有重复的条目,这两者都不匹配 DataFrame 对象实现。

另一种可能性(从查看代码来看更有可能)是,由于合并操作不假设列已排序,因此它会在应用更像数组的合并之前对列本身进行排序。这意味着预排序不会产生任何影响,因为合并无论如何都会对列进行重新排序。

pandas DataFrame 对象代码可以在这里找到 ,DataFrame 合并操作的合并操作可以在这里找到。