【问题标题】:Pandas concat in a loop vs list.append循环中的 Pandas concat vs list.append
【发布时间】:2022-08-17 22:27:12
【问题描述】:

我使用了 2 种方法在 pandas 中创建了一个全局 df,每一行都是由另一个 df 的过滤产生的。我通过在循环生成的计算列中查找最小值进行过滤,但我读到最好避免在循环内存中使用pd.concat。 与另一种方法相比,在时间上似乎没有太大的差异。 有没有更好的方法?

import time
import pandas as pd

technologies = {
    \'X\' :[20000,25000,22000,30000,50000,10000,30000],
    \'Y\':[1000,2300,1200,2000,1000,3000,5000]
          }
df = pd.DataFrame(technologies)
start_time = time.time()
df1_result=pd.DataFrame()
for i in range(df.shape[0]):
    df1=df.copy()
    df1[\'i\']=i
    df1[\'Y\']=df1[\'Y\'].shift(-i)
    df1[\'Dist\']=df1[\'X\']-df1[\'Y\']
    idmin=df1[\'Dist\'].idxmin()
    result=pd.DataFrame([df1.iloc[idmin,:]])
    df1_result=pd.concat(([df1_result, result]),  ignore_index=True)
print(\"--- %s seconds ---\" % (time.time() - start_time))

start_time = time.time()
ListResult2=[]
for i in range(df.shape[0]):
    df2=df.copy()
    df2[\'i\']=i
    df2[\'Y\']=df2[\'Y\'].shift(-i)
    df2[\'Dist\']=df2[\'X\']-df2[\'Y\']
    idmin=df2[\'Dist\'].idxmin()
    ListResult2.append(df2.iloc[idmin,:].values.tolist())

df_result2 = pd.DataFrame (ListResult2)

    标签: python pandas memory arraylist concatenation


    【解决方案1】:

    这是您正在做的事情的重构版本:

    rows = list()
    for i in range(df.shape[0]):
        s = df.X-df.Y.shift(-i)
        idx_min = s.idxmin()
        row = [df.X[idx_min], df.Y.shift(-i)[idx_min], i, s[idx_min]]
        rows.append(row)
    
    result = pd.DataFrame(rows, columns=['X','Y','i','Dist'])
    print(result)
    
           X       Y  i     Dist
    0  10000  3000.0  0   7000.0
    1  10000  5000.0  1   5000.0
    2  20000  1200.0  2  18800.0
    3  20000  2000.0  3  18000.0
    4  22000  5000.0  4  17000.0
    5  20000  3000.0  5  17000.0
    6  20000  5000.0  6  15000.0
    

    你的第二种方法肯定比第一种更快。如果我像这样对每种方法进行测试:

    import timeit
        
    a_dict = {}
    
    mysetup = """import pandas as pd
    technologies = {
        'X' :[20000,25000,22000,30000,50000,10000,30000],
        'Y':[1000,2300,1200,2000,1000,3000,5000]
              }
    df = pd.DataFrame(technologies)
    """
    
    mycode = '''
    df1_result=pd.DataFrame()
    for i in range(df.shape[0]):
        df1=df.copy()
        df1['i']=i
        df1['Y']=df1['Y'].shift(-i)
        df1['Dist']=df1['X']-df1['Y']
        idmin=df1['Dist'].idxmin()
        result=pd.DataFrame([df1.iloc[idmin,:]])
        df1_result=pd.concat(([df1_result, result]),  ignore_index=True)
    '''
    
    a_dict['method 1'] = timeit.timeit(setup = mysetup,stmt = mycode,number = 10000)
    
    # and then for method 2, 3 in the same way...
    

    结果如下:

    timed = pd.DataFrame.from_dict(a_dict, orient='index', columns=['time (seconds)'])
    timed['perc'] = timed['time (seconds)']/timed['time (seconds)'].max()
    
    print(timed)
    
              time (seconds)      perc
    method 1      111.176106  1.000000
    method 2       87.288192  0.785134
    method 3       24.884230  0.223827
    

    因此,您的第二种方法将执行时间减少了大约 21%,而重构版本将执行时间减少了大约 77%。我相信其他用户可以找到一种方法让它运行得更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-16
      • 2016-03-11
      • 1970-01-01
      • 1970-01-01
      • 2012-10-02
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      相关资源
      最近更新 更多