Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 复制数据帧行并同时更新数据帧值的有效方法_Python_Pandas_Dataframe_Date_Optimization - Fatal编程技术网

Python 复制数据帧行并同时更新数据帧值的有效方法

Python 复制数据帧行并同时更新数据帧值的有效方法,python,pandas,dataframe,date,optimization,Python,Pandas,Dataframe,Date,Optimization,我需要一些帮助来优化我的python代码。代码根据数据帧中的一行中的值多次复制该行 我将尝试描述它的功能: 数据框有三个日期列:拆分日期、开始日期和结束日期,以及一个状态列,其中包含“in”或“out”。dataframe将有更多列,但其余列在算法中并不重要 它使用溢出日期的mm/dd来创建 开始日期和结束日期之间的日期。假设拆分日期为2000-02-15,开始日期为2010-03-26,并且 截止日期为2012年12月31日。日期列表将为2010年03月26日、2011年02月15日, 2

我需要一些帮助来优化我的python代码。代码根据数据帧中的一行中的值多次复制该行

我将尝试描述它的功能:

  • 数据框有三个日期列:拆分日期、开始日期和结束日期,以及一个状态列,其中包含“in”或“out”。dataframe将有更多列,但其余列在算法中并不重要

  • 它使用溢出日期的mm/dd来创建 开始日期和结束日期之间的日期。假设拆分日期为2000-02-15,开始日期为2010-03-26,并且 截止日期为2012年12月31日。日期列表将为2010年03月26日、2011年02月15日, 2012-02-15和2012-12-31

  • 根据日期列表,它将复制原始dataframe行和 用日期列表中的日期替换开始日期和结束日期。 使用相同的示例,原始行将被复制 三次,开始日期和结束日期为:

  • 2010-03-26和2011-02-15

  • 2011-02-15和2012-02-15

  • 2012-02-15和2012-12-31

  • 除最后一行的状态与原始行相同外,所有新创建的行的状态均为“in”。以同样的例子:

  • 如果原始行中的状态为“in”,则三个重复行的状态为“in”
  • 如果原始行中的状态为“out”,则新创建行的第一行和第二行的状态为“in”,第三行的状态为“out”
我尝试了不同的方法来完成上面的任务,并想出了我能想到的最有效的代码,但我仍然对它的性能不是很满意

我有一个巨大的数据框架,有许多列和数十万行(仍在扩展),运行它需要一段时间。多处理稍微减少了运行时间,但我认为核心算法可能会进一步优化

这项任务最初是在SAS中执行的,在SAS中执行起来要快得多。我不确定python是否一般比SAS慢,或者我的代码没有优化,因此非常感谢您的建议和意见

我的python代码:

import pandas as pd
import numpy as np

data = {"name": ["a","b","c","d"],
       "status": ["out","out","in","out"],
       "split_date": ["2000-02-15","2010-12-31","1984-02-29","2000-03-31"],
       "start_date": ["2010-03-26","2010-01-01","2015-06-15","2012-11-18"],
       "end_date": ["2012-12-31","2015-12-31","2020-03-01","2018-07-19"]}

df = pd.DataFrame(data)
df["split_date"]=pd.DatetimeIndex(df["split_date"]).normalize()
df["start_date"]=pd.DatetimeIndex(df["start_date"]).normalize()
df["end_date"]=pd.DatetimeIndex(df["end_date"]).normalize()



def to_split(df,start_column,end_column,split_column):
    """
    df = name of the dataframe whose dates are to be split
    
    start_column = column name of start date
    
    end_column = column name of end date
      
    split_column = column name of split date (only mm-dd of the date will be used)
    
    """
    
    
    dict_df = df.to_dict(orient="index")
    
    dictionary_list=[]
    
    
    for key,row_dict in dict_df.items():
        
        first_date=row_dict[start_column]
        last_date=row_dict[end_column]
        
                
        if last_date < first_date:
            raise ValueError("end_column_date is before start_column_date.")

        try:
            splitter = pd.Timestamp(first_date.year,row_dict[split_column].month,row_dict[split_column].day)
        except: #leap day
            splitter = pd.Timestamp(first_date.year,row_dict[split_column].month,row_dict[split_column].day-1)                    


        #Create a date list to store intermediate split date between first_date and last_date 
        date_list=[]
        date_list.append(first_date)

        last_boolean=False
        while last_boolean == False:
            if splitter <= first_date and splitter <= last_date:

                try:
                    splitter = pd.Timestamp(splitter.year+1,row_dict[split_column].month,
                                            row_dict[split_column].day)
                except:  #leap day
                    splitter = pd.Timestamp(splitter.year+1,row_dict[split_column].month,
                                                row_dict[split_column].day-1)

            elif splitter > first_date and splitter <= last_date:
                date_list.append(splitter)
                
                try:
                    splitter = pd.Timestamp(splitter.year+1,row_dict[split_column].month,
                                            row_dict[split_column].day)
                except:  #leap day
                    splitter = pd.Timestamp(splitter.year+1,row_dict[split_column].month,
                                                row_dict[split_column].day-1)

            else: #splitter > last_date
                date_list.append(last_date)
                last_boolean = True

        #convert list to dictionary first to remove any duplicate then convert back to list again
        date_list = list(dict.fromkeys(date_list))
        date_list.sort()       
        
        no_segment = len(date_list)-1
        status=row_dict["status"]
        
        for i in range(no_segment):           
            
            #Assign new start and end date to each newly created row
            row_dict["start_column_date"]=date_list[i]
            row_dict["end_column_date"]=date_list[i+1]                     
            
            #Assign new status to each newly created row           
            if i != no_segment-1:
                row_dict["status"] = "in"
            else:
                row_dict["status"] = status
                
            
            #dictionary_list.append(row_dict)
            #results will be wrong because list contains a reference to the original dictionary 
         
            dictionary_list.append(row_dict.copy()) 

    new_df=pd.DataFrame.from_dict(dictionary_list)
            
    return new_df


expanded_df=to_split(df,"start_date","end_date","split_date")
expanded_df
将熊猫作为pd导入
将numpy作为np导入
数据={“名称”:[“a”、“b”、“c”、“d”],
“状态”:[“输出”、“输出”、“输入”、“输出”],
“拆分日期”:[“2000-02-15”、“2010-12-31”、“1984-02-29”、“2000-03-31”],
“开工日期”:[“2010-03-26”、“2010-01-01”、“2015-06-15”、“2012-11-18”],
“结束日期”:[“2012-12-31”、“2015-12-31”、“2020-03-01”、“2018-07-19”]
df=pd.DataFrame(数据)
df[“分割日期”]=pd.DatetimeIndex(df[“分割日期”]).normalize()
df[“开始日期”]=pd.DatetimeIndex(df[“开始日期”]).normalize()
df[“结束日期”]=pd.DatetimeIndex(df[“结束日期”]).normalize()
def到_拆分(df、开始_列、结束_列、拆分_列):
"""
df=要拆分其日期的数据帧的名称
开始\列=开始日期的列名
结束\列=结束日期的列名
split_column=拆分日期的列名(仅使用日期的mm dd)
"""
dict_df=df.to_dict(orient=“index”)
字典列表=[]
对于键,dict_df.items()中的行dict:
第一个日期=行记录[开始列]
最后日期=行记录[结束列]
如果最后日期<第一日期:
raise VALUE ERROR(“结束列日期早于开始列日期”)
尝试:
splitter=pd.Timestamp(第一个日期.年,行记录[拆分列]。月,行记录[拆分列]。天)
除了:#闰日
splitter=pd.Timestamp(第一个日期.年,行记录[拆分列]。月,行记录[拆分列]。第1天)
#创建日期列表以存储第一个日期和最后一个日期之间的中间拆分日期
日期列表=[]
日期列表。附加(第一个日期)
最后一个布尔值=False
而last_boolean==False:

如果根据我的经验,斯普利特提出了大量文本和大量代码的问题,却得不到任何答案,那么就没有人愿意通读所有文本和代码来理解问题所在。尽量简短扼要。我自己的一个问题,看到区别了吗?太多了,无法理解-但是在数据帧上迭代总是一个坏主意。将范例从循环切换到基于最佳向量,或者使用掩码和子掩码。我知道在数据帧上迭代是个坏主意。我曾尝试使用矢量化操作,但我不认为它可以在这种情况下使用,因为我实际上是根据每一行的输入创建新行。我可能会错过一些东西,所以一些关于矢量化操作的指针会很好。根据我的经验,有大量文本和大块代码的问题不会得到任何答案,没有人想通过所有文本和代码来理解问题是什么。尽量简短扼要。我自己的一个问题,看到区别了吗?太多了,无法理解-但是在数据帧上迭代总是一个坏主意。将范例从循环切换到基于最佳向量,或者使用掩码和子掩码。我知道在数据帧上迭代是个坏主意。我曾尝试使用矢量化操作,但我不认为它可以在这种情况下使用,因为我实际上是根据每一行的输入创建新行。我可能会错过一些东西,所以向量化操作上的一些指针会很好。