首页 > 解决方案 > 数据帧性能问题与排列

问题描述

我想知道是什么导致了这个性能问题。

问题:CPU 100%,需要几个小时才能完成。

df1.size : 2.5m

df2.size : 264k

df1:

Index B
A1  B1
A1  B3
A2  B2
...
A3  B1
A3  B4
A4  B7
A5  B3

df2:

Index C
A1  C1
A1  C2
A2  C1
...
A3  C1
A3  C2
A4  C1

我想使用 df2 的索引(不是唯一的)来匹配 df1 的索引中的相同值(不是唯一的)来获得 B(Bx) 和 C(Cx) 的排列

我的代码:

//This operation DO NOT have performance issue
//get Intersection of Index of df1 and df2 to avoid Exception
Index_df2_deduplicated = df2.index.drop_duplicates()
Index_FullList = []
for i in range(Index_df2_deduplicated.size):
    Index_FullList.append(Index_df2_deduplicated[i])
IntersectionIndexs = df1.index.intersection(Index_FullList).drop_duplicates()

//This cause CPU 100% and take several hours to finish.
i = 0
for i in range(IntersectionIndexs.size):
    B = df1.loc[IntersectionIndexs[i],'B']
    C = df2.loc[IntersectionIndexs[i],'C']
    if isinstance(B, (unicode)) == True:
        B = [B]
    elif isinstance(B, (pd.core.series.Series)) == True:
        B = B.drop_duplicates().reset_index(drop=True).tolist()
    if isinstance(C, (unicode)) == True:
        C = [C]
    elif isinstance(C, (pd.core.series.Series)) == True:
        C = C.drop_duplicates().reset_index(drop=True).tolist()
    lists = [B, C]
    Output = pd.DataFrame(list(itertools.product(*lists)), columns=['B', 'C'])
    Output.to_csv("output.txt", mode='a', index=False, header=False)

标签: pythonpandasdataframepermutation

解决方案


Pandas 带有笛卡尔连接能力:

pd.merge(df1, df2, on="key")

您的代码涉及显式创建太多不必要的对象。此外,在 Python 中对此类对象的操作可能非常昂贵,因为 Python 是一种动态类型语言,尤其是对于迭代和合并。

一些直接的建议:

  • 不要重新发明轮子。尽可能多地使用库提供的函数,因为它们已被那些有经验的库作者优化到合理的程度。
  • 如果您觉得您的任务属于某种可概括的逻辑,请务必先询问 StackOverflow 或 google。例如,在 google 上搜索“Cartesian join pandas”,您很可能会找到这个答案,这将为您节省大量时间。

注意数据清理部分被忽略了,因为它不是这个问题的主要课程。

代码

import pandas as pd
# data
df1 = pd.DataFrame(
    data={
        "Index": ['a1', 'a1', 'a2', 'a3', 'a3', 'a3',],
        "B": [1,2,3,4,5,6]
    }
)
df2 = pd.DataFrame(
    data={
        "Index": ['a1', 'a1', 'a2', 'a2', 'a3', 'a3'],
        "C": [.1,.2,.3,.4,.5,.6]
    }
)
df1 = df1.set_index("Index")
df2 = df2.set_index("Index")

# task
df_ans = pd.merge(df1, df2, on="Index")

输出

df

# as eapected: 2*2 a1's + 1*2 a2's + 3*2 a3's in order
Out[5]: 
       B    C
Index        
a1     1  0.1
a1     1  0.2
a1     2  0.1
a1     2  0.2
a2     3  0.3
a2     3  0.4
a3     4  0.5
a3     4  0.6
a3     5  0.5
a3     5  0.6
a3     6  0.5
a3     6  0.6

推荐阅读