我发现,当您将大量数据集与同一列的大量列合并时,与pandas库直接进行链合并效率非常低。
问题的根源与我们加入很多str愚蠢的方式时一样: joined = reduce(lambda a + b,str_list) 代替: 加入=''。join(str_list)
进行链合并我们多次复制数据集(在我的情况下几乎100次),而不是一次或按顺序填充几个数据集中的列
是否有一些有效的方法(=具有线性复杂度的集合数量)来链接合并很多数据集的同一列?
答案 0 :(得分:4)
如果您有数据框列表dfs
:
dfs = [df1, df2, df3, ... , dfn]
你可以使用熊猫concat
函数加入他们,据我所知,这比链接合并更快。 concat
仅基于索引(不是列)加入数据帧,但通过一些预处理,您可以模拟merge
操作。
首先将dfs
中每个数据框的索引替换为要合并的列。假设您要在列"A"
上合并:
dfs = [df.set_index("A", drop=True) for df in dfs]
请注意,将覆盖以前的索引(无论如何合并都会执行此操作),因此您可能希望将这些索引保存在某处(如果由于某种原因您将在以后需要它们)。
现在我们可以使用concat,它基本上会合并到索引上(实际上是你的列 !!)
merged = pd.concat(dfs, axis=1, keys=range(len(dfs)), join='outer', copy=False)
join=
参数可以是'inner'
或'outer'
(默认)。 copy=
参数使concat
不会对数据帧进行不必要的复制。
然后您可以将"A"
作为索引,也可以通过执行以下操作将其恢复为列:
merged.reset_index(drop=False, inplace=True)
keys=
参数是可选的,并为每个数据帧分配一个键值(在这种情况下,我为它提供了一系列整数,但如果需要,可以给它们其他标签)。这允许您从原始数据帧访问列。因此,如果您希望获得与dfs
中的第20个数据框相对应的列,则可以调用:
merged[20]
如果没有keys=
参数,可能会混淆哪些行来自哪些数据帧,特别是如果它们具有相同的列名。
我还不完全确定concat
是否以线性时间运行,但肯定比链接merge
更快:
在随机生成的数据帧列表中使用ipython的%timeit(10,100和1000个数据帧的列表):
def merge_with_concat(dfs, col):
dfs = [df.set_index(col, drop=True) for df in dfs]
merged = pd.concat(dfs, axis=1, keys=range(len(dfs)), join='outer', copy=False)
return merged
dfs10 = [pd.util.testing.makeDataFrame() for i in range(10)]
dfs100 = [pd.util.testing.makeDataFrame() for i in range(100)]
dfs1000 = [pd.util.testing.makeDataFrame() for i in range(1000)]
%timeit reduce(lambda df1, df2: df1.merge(df2, on="A", how='outer'), dfs10)
10 loops, best of 3: 45.8 ms per loop
%timeit merge_with_concat(dfs10,"A")
100 loops, best of 3: 11.7 ms per loop
%timeit merge_with_concat(dfs100,"A")
10 loops, best of 3: 139 ms per loop
%timeit reduce(lambda df1, df2: df1.merge(df2, on="A", how='outer'), dfs100)
1 loop, best of 3: 1.55 s per loop
%timeit merge_with_concat(dfs1000,"A")
1 loop, best of 3: 9.67 s per loop
%timeit reduce(lambda df1, df2: df1.merge(df2, on="A", how='outer'), dfs1000)
# I killed it after about 5 minutes so the other one is definitely faster