如何提高用于python数据帧的嵌套for循环的性能

2024-06-09 15:31:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在为dataframe使用嵌套for循环,但我的文件包含很多行(近96k行)。我应该如何提高我的速度。现在运行我的代码需要几个小时。谁能帮我一下吗。我也试着使用麻木Jit,但它仍然需要很长时间。 我研究了很多关于如何获得我的代码,但还没有任何解决方案。我试图考虑使用lambda,但不确定如何在这里具体使用它。不确定矢量化。如果可能的话,有人能帮我一下吗

下面是我的代码--

import xlsxwriter

excelFile = xlsxwriter.Workbook ("FlagResult.xlsx")
workSheet = excelFile.add_worksheet ()

import pandas as pd
import numpy as np
import math
from datetime import datetime
from numba import jit



df= pd.read_csv('Coconut_data.csv')
site= df['Site']
month= df['Month']
year= df['Year']
data_source= df['Data Source']
source_type = df['Sourcetype']

# df19= df[df['Year']==2019]
df19= df[df['Year']==2019]
site19= df19['Site']
month19= df19['Month']
year19= df19['Year']
st19= df19['Sourcetype']

df20= df[df['Year']==2020]
site20= df20['Site']
month20= df20['Month']
year20= df20['Year']
st20= df20['Sourcetype']

df21= df[df['Year']==2021]
site21= df21['Site']
month21= df21['Month']
year21= df21['Year']
st21= df21['Sourcetype']

df19['Unique19']= site19.map(str) + month19.map(str) + st19.map(str)
df20['Unique20']= site20.map(str) + month20.map(str) + st20.map(str)
df21['Unique21']= site21.map(str) + month21.map(str) + st21.map(str)


df19['Uniquex19']= site19.map(str) + month19.map(str)
df20['Uniquex20']= site20.map(str) + month20.map(str)
df21['Uniquex21']= site21.map(str) + month21.map(str)

pivot19 = pd.pivot_table(df19,index=['Unique19','Data Source','Sourcetype','Site','Month','Year','Uniquex19'],values=['Final Usage'], aggfunc=np.sum)
pivot20 = pd.pivot_table(df20,index=['Unique20','Data Source','Sourcetype','Site','Month','Year','Uniquex20'],values=['Final Usage'], aggfunc=np.sum)
pivot21 = pd.pivot_table(df21,index=['Unique21','Data Source','Sourcetype','Site','Month','Year','Uniquex21'],values=['Final Usage'], aggfunc=np.sum)

# print(pivot19, pivot20, pivot21)
 
print('\n')
print('\n')   
           
@jit

def check2019(): 
    r=1
    for index, values in pivot19.iterrows():
        
        if (index[1]=='Actuals'):
            count=0
            for idx, val in pivot20.iterrows():
                if(idx[1]=='Actuals'):
                    if (index[6]==idx[6]):
                        per= ((val-values)/values)*100
                        if (per > 50).bool():
                            if (per == math.inf).bool():
                                result= 'Usage was 0 for ', str(index[3]), ' in ', str(index[4]), str(index[5]), ' but not for ', str(idx[5])
                                count+=1
                                r+=1
                                res = ''.join(result)
                                print(res)
                                workSheet.write(r,1,str(res))
                                break
                            else:
                                 result= str(index[3]) ,' for ', str(index[4]), str(index[5]), ' from ', str(index[2]), ' has increased by ', str(abs(round(float(per),2))), ' % in ', str(idx[5])
                                 count+=1
                                 r+=1
                                 res = ''.join(result)
                                 print(res)
                                 workSheet.write(r,1,str(res))
                                 break
                                 
                        elif (per < -50).bool():
                            result= str(index[3]) ,' for ', str(index[4]), str(index[5]), ' from ', str(index[2]), ' has dropped by ', str(abs(round(float(per),2))), ' % in ', str(idx[5])
                            count+=1
                            r+=1
                            res = ''.join(result)
                            print(res)
                            workSheet.write(r,1,str(res))
                            break
                            
                        else:
                            # result= 'No spike or drop observed for ', str(index[3]), ' in ', index[4], str(index[5])
                            # count+=1
                            # r+=1
                            # res = ''.join(result)
                            # print(res)
                            # workSheet.write(r,1,str(res))
                            break
                            
            if count==0:
                result= 'Missing ', str(index[3]), ' in ', str(index[4]), ' ', str(idx[5])
                r+=1
                res = ''.join(result)
                print(res)
                workSheet.write(r,1,str(res))
                
                
check2019()

Tags: mapdfforindexsiteresresultyear
2条回答

在矢量化或改进for循环方面,要给你一个更精确的答案有点棘手,因为你看不到底层数据,也不知道你在对它做什么

然而,在我看来,在嵌套for循环中,似乎有很多特定的东西正在进行,这些东西已经可以工作了

因此,这种方法可能是一种更简洁的解决方案。。。它将数据帧分割成块,这样您就可以使用生成器表达式一次处理一个块,这将节省大量系统内存。这将大大提高性能,并有望使您不必大幅重写for循环逻辑

def split_df_into_chunks(df, n):
    """
    Splits a dataframe into n chunks so each one can be processed at a time.
    :param df: pandas dataframe.
    :param n: int, number of rows to include in each chunk.
    :return chunks: generator expression.
    """
    chunks = (df.loc[x : x + n - 1] for x in list(range(len(df)))[::n])
    return chunks

df_sections = split_df_into_chunks(your_df, 3)

try:
    while True:
        check2019(next(df_sections))
except StopIteration:
    print('Finished processing dataframes')
finally:
    del df_sections

这不是一个答案,而是要表明您需要考虑从代码中获得什么,并寻找现有的功能。很可能以前有人做过类似的事情,或者API中有标准方法可以快速处理您的输入。仅举一个例子

例如,如果您想进行百分比更改比较,您可以查看pct_change并尝试

import pandas as pd

values = pd.date_range('2021-01-01', periods=3, freq='5W')

df = pd.DataFrame({'SiteA': [75.52,75.12,85.21],'SiteB': [70.21,69.21,72.21],'SiteC':[90.14,82.1,45.27]}, index=values)

print(round(df.pct_change(axis=0),2))

这将产生:

            SiteA   SiteB   SiteC
2021-01-03  NaN     NaN     NaN
2021-02-07  -0.01   -0.01   -0.09
2021-03-14  0.13    0.04    -0.45

您应该注意到,我不是在写per= ((val-values)/values)*100,其中valvalues来自数据帧上的for循环;我不是说在哪里写

现在,它的输入是这样的数据帧

            SiteA   SiteB   SiteC
2021-01-03  75.52   70.21   90.14
2021-02-07  75.12   69.21   82.10
2021-03-14  85.21   72.21   45.27

第一步是尽可能地整理(清理、移动、洗牌、移位等)数据输入,并使其尽可能有条理。然后环顾四周(搜索)“我如何比较一年与另一年的百分比变化”…等等。如果你陷入困境(我们都是这样),你应该发布一个新问题,并说“这是我代码的一部分……它可以做到这一点,但我希望它能做到这一点。我尝试过这一点……但它出现了错误

代码可能已经存在了

相关问题 更多 >