Python如何优化代码以更快地运行?(数据帧中有很多for循环)

2024-06-09 05:13:03 发布

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

我有一个可以广泛使用excel文件(SAP下载)的代码(数据转换和计算步骤)。
我需要将所有行(几千行)循环几次。我之前写过一段代码,分别添加数据帧列,因此我可以在一个for循环中完成所有操作,当然这相当快,但是,我必须更改数据源,这意味着原始数据结构的更改。
原始数据结构的前3行为空,然后标题行带有列名,然后2行为空,第一列也为空。我决定删除这些,并分配列名并使其成为标题(以下步骤),但是,从那时起,单独添加列名并在一个for语句中计算所有内容并不会将数据填充到这些特定列中。
如何优化此代码

我删除了一些计算步骤,因为它们相当长,使代码部分的可读性更低

#This function adds new column to the dataframe  
def NewColdfConverter(*args):  
    for i in args:   
        dfConverter[i] = '' #previously used dfConverter[i] = NaN  


#This function creates dataframe from excel file  
def DataFrameCreator(path,sheetname):  
    excelFile = pd.ExcelFile(path)  
    global readExcel  
    readExcel = pd.read_excel(excelFile,sheet_name=sheetname)  



#calling my function to create dataframe  
DataFrameCreator(filePath,sheetName)  
dfConverter = pd.DataFrame(readExcel)  
  
#dropping NA values from Orders column (right now called Unnamed)  
dfConverter.dropna(subset=['Unnamed: 1'], inplace=True)  
  
#dropping rows and deleting other unnecessary columns  
dfConverter.drop(dfConverter.head(1).index, inplace=True)  
dfConverter.drop(dfConverter.columns[[0,11,12,13,17,22,23,48]], axis = 1,inplace = True)  
  
#renaming columns from Unnamed 1: etc to proper names  
dfConverter = dfConverter.rename(columns={Unnamed 1:propername1 Unnamed 2:propername2 etc.})  
  
#calling new column function -> this Day column appears in the 1st for loop  
NewColdfConverter("Day")  

  
#example for loop that worked prior, but not working since new dataset and new header/column steps added:  
for i in range(len(dfConverter)):      
    #Day column-> floor Entry Date -1, if time is less than 5:00:00
    if(dfConverter['Time'][i] <= time(hour=5,minute=0,second=0)):  
        dfConverter['Day'][i] = pd.to_datetime(dfConverter['Entry Date'][i])-timedelta(days=1)  
    else:  
        dfConverter['Day'][i] = pd.to_datetime(dfConverter['Entry Date'][i])  

问题是,有许多列彼此构建,所以我无法在一个for循环中获取它们,例如,在下面的示例中,我需要计算reqsWoSetUpValue,这样我就可以计算requirementsValue,这样我就可以计算其他ReqsValue,但我无法通过将值分配给dataframecolumn[I]行在1 for循环中实现这一点,因为值将丢失,就像什么都没有发生一样。
(dfsorted与dfConverter相同,但它是一个排序版本)

#example code of getting reqsWoSetUpValue  
for i in range(len(dfSorted)):  
    reqsWoSetUpValue[i] = #calculationsteps...  
#inserting column with value  
dfSorted.insert(49,'Reqs wo SetUp',reqsWoSetUpValue)  
  
#getting requirements value with previously calculated Reqs wo SetUp column  
for i in range(len(dfSorted)):  
    requirementsValue[i] = #calc  
  
dfSorted.insert(50,'Requirements',requirementsValue)  
  
#Calculating Other Reqs value with previously calculated Requirements column.  
for i in range(len(dfSorted)):  
    otherReqsValue[i] = #calc  
  
dfSorted.insert(51,'Other Reqs',otherReqsValue)  
  

任何人都有一个线索,为什么我不能在1 for循环中通过首先通过函数添加所有列来实现这一点,比如:

NewColdfConverter('Reqs wo setup','Requirements','Other reqs')  
  
#then in 1 for loop:  
for i in range(len(dfsorted)):  
    dfSorted['Reqs wo setup'] = #calculationsteps  
    dfSorted['Requirements'] = #calculationsteps  
    dfSorted['Other reqs'] = #calculationsteps  
  

多谢各位


Tags: to代码innewforlenrangefunction
2条回答

不确定这是否会提高性能,但可以使用DataFrame.iterrows()同时逐行计算依赖列

for index, data in dfSorted.iterrows():
    dfSorted['Reqs wo setup'][index] = #calculationsteps  
    dfSorted['Requirements'][index] = #calculationsteps  
    dfSorted['Other reqs'][index] = #calculationsteps  

一般性意见:如何识别瓶颈

要开始,您应该尝试识别代码的哪些部分比较慢

方法1:使用time包的时间代码部分

将代码块包装在如下语句中:

import time
t = time.time()

# do something

print("time elapsed: {:.1f} seconds".format(time.time() - t))

方法2:使用探查器

Spyder有一个内置的探查器。这允许您检查哪些操作最耗时

矢量化您的操作

如果对操作进行向量化,代码的速度将提高几个数量级。看起来你的循环都是可以避免的

例如,与其对每一行分别调用pd.to_datetime,不如对整个列同时调用它

# slow (don't do this):
for i in range(len(dfConverter)):
   dfConverter['Day'][i] = pd.to_datetime(dfConverter['Entry Date'][i])

# fast (do this instead):
dfConverter['Day'] = pd.to_datetime(dfConverter['Entry Date'])

如果要对行的子集执行操作,也可以使用loc在矢量化操作中执行此操作:

mask = dfConverter['Time'] <= time(hour=5,minute=0,second=0)
dfConverter.loc[mask,'Day'] = pd.to_datetime(dfConverter.loc[mask,'Entry Date']) - timedelta(days=1)

相关问题 更多 >