mor*_*rph 5 python merge pandas
我发现,当您将大量数据集与同一列的大量列合并时,与 Pandas 库的直接链合并效率非常低。
问题的根源和我们加入很多str的愚蠢方式是一样的:
joined = reduce(lambda a + b, str_list)
Run Code Online (Sandbox Code Playgroud)
代替:
joined = ''.join(str_list)
Run Code Online (Sandbox Code Playgroud)
在进行链合并时,我们多次复制数据集(在我的情况下几乎是 100 次),而不是一次或按顺序填充来自多个数据集的列。
是否有一些有效的方法(= 具有线性复杂度的集合)通过同一列链接合并大量数据集?
如果您有数据框列表dfs:
dfs = [df1, df2, df3, ... , dfn]
Run Code Online (Sandbox Code Playgroud)
您可以使用 panda 的concat函数加入它们,据我所知,它比链接合并更快。concat仅基于索引(而不是列)连接数据帧,但通过一些预处理,您可以模拟merge操作。
首先用dfs要合并的列替换每个数据帧的索引。假设您想在 column 上合并"A":
dfs = [df.set_index("A", drop=True) for df in dfs]
Run Code Online (Sandbox Code Playgroud)
请注意,这将覆盖以前的索引(无论如何合并都会这样做),因此您可能希望将这些索引保存在某处(如果您以后由于某种原因需要它们)。
现在我们可以使用 concat 来合并索引(实际上是你的列!!)
merged = pd.concat(dfs, axis=1, keys=range(len(dfs)), join='outer', copy=False)
Run Code Online (Sandbox Code Playgroud)
所述join=参数可以是'inner'或'outer'(默认)。该copy=参数concat避免制作不必要的数据帧副本。
然后,您可以将其保留"A"为索引,也可以通过执行以下操作将其重新放入列中:
merged.reset_index(drop=False, inplace=True)
Run Code Online (Sandbox Code Playgroud)
该keys=参数是可选的,并为每个数据帧分配一个键值(在这种情况下,我给了它一个整数范围,但如果需要,您可以给它们其他标签)。这允许您访问原始数据帧中的列。因此,如果您想获取与第 20 个数据帧对应的列,dfs可以调用:
merged[20]
Run Code Online (Sandbox Code Playgroud)
如果没有keys=参数,可能会混淆哪些行来自哪些数据帧,特别是如果它们具有相同的列名。
我仍然不完全确定是否concat在线性时间内运行,但它肯定比链接更快merge:
在随机生成的数据帧列表(10、100 和 1000 个数据帧的列表)上使用 ipython 的 %timeit:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3947 次 |
| 最近记录: |