timeseries 데이터 프레임에 행을 추가하는 방법은 무엇입니까?

Dec 31 2020

timeseries 엑셀 파일에서 데이터 프레임에로드되는 프로그램을 작성하고 있으며 몇 가지 기본 계산을 사용하여 여러 개의 새 열을 만듭니다. 내 프로그램은 때때로 일부 레코드에 대해 몇 달이 누락 된 Excel 파일을 읽을 것입니다. 따라서 아래 예에는 두 개의 다른 상점에 대한 월별 판매 데이터가 있습니다. 상점은 다른 달에 열리므로 첫 번째 월말 날짜가 다릅니다. 그러나 둘 다 2020 년 9 월 30 일까지 월말 데이터를 가져야합니다. 내 파일에서 Store BBB에는 2020 년 8 월 31 일 및 2020 년 9 월 30 일에 대한 기록이 없습니다.

저장 개설 된 달 상태 시티 월 종료일 매상
AAA 2020 년 5 월 31 일 NY 뉴욕 2020 년 5 월 31 일 1000
AAA 2020 년 5 월 31 일 NY 뉴욕 2020 년 6 월 30 일 5000
AAA 2020 년 5 월 31 일 NY 뉴욕 2020 년 7 월 30 일 3000
AAA 2020 년 5 월 31 일 NY 뉴욕 2020 년 8 월 31 일 4000
AAA 2020 년 5 월 31 일 NY 뉴욕 2020 년 9 월 30 일 2000 년
BBB 2020 년 6 월 30 일 CT Hartford 2020 년 6 월 30 일 100
BBB 2020 년 6 월 30 일 CT Hartford 2020 년 7 월 30 일 200

따라서 이와 같은 인스턴스의 경우 8/31 및 9/30에 대해 Store BBB에 대해 두 행을 추가 할 수 있기를 원합니다. 새 행은 가장 최근의 월말 날짜와 동일한 개설 된 월, 주 및시를 사용해야합니다. 새 행 모두에 대해 Sales를 0으로 설정해야합니다. 지금은 다음 단계를 수행합니다.

  1. 상점 이름과 각 상점에 대한 최대 월 종료 날짜 및 전체 시계열 데이터 프레임에 대한 최대 월 종료 날짜를 사용하여 데이터 프레임 "MaxDateData"를 작성하고이 필드의 이름을 "가장 최근 날짜"로 지정합니다.
저장 최대 월 종료 날짜 가장 최근 날짜
AAA 2020 년 9 월 30 일 2020 년 9 월 30 일
BBB 2020 년 7 월 30 일 2020 년 9 월 30 일
  1. 기본 시계열 데이터 프레임의 가장 최근 행으로 "MostRecent"데이터 프레임을 만듭니다. 이를 위해 시계열 데이터 프레임과 Store Name 및 Max Month End Date의 MaxDateData 사이에 내부 조인을 수행합니다.
저장 개설 된 달 상태 시티 월 종료일 매상 최대 월 종료 날짜 가장 최근 날짜
AAA 2020 년 5 월 31 일 NY 뉴욕 2020 년 9 월 30 일 2000 년 2020 년 9 월 30 일 2020 년 9 월 30 일
BBB 2020 년 6 월 30 일 CT Hartford 2020 년 7 월 30 일 200 2020 년 7 월 30 일 2020 년 9 월 30 일
  1. Where 절을 사용하여 "RequireBackfill_MostRecent"데이터 프레임을 만들어 최대 월 종료 날짜 <가장 최근 날짜 인 상점을 필터링합니다. 아래 코드를 참조하십시오. 따라서이 예에서 RequireBackfill_MostRecent 테이블에는 상점 BBB에 대한 행만 있습니다.
RequireBackfill_Stores_MostRecent = MaxDateData.where(MaxDateData['Max Month End Date'] <MaxDateData['Most Recent Date'])
RequireBackfill_MostRecent = MostRecent.merge(RequireBackfill_Stores_MostRecent,how='inner')
  1. 그런 다음 두 개의 중첩 된 for 루프를 사용하여 채워야하는 날짜를 순환합니다. Store BBB 만 포함하는 RequireBackfill_MostRecent 데이터 프레임을 활용합니다.
X=[]
end = MaxDateData['Most Recent Date'][0]
for i in MonthlyData['Month End Date'].unique():
    per1 = pd.date_range(start = i,  end = end, freq ='M') 
    for val in per1: 
        Data=[]
        Data = RequireBackfill_MostRecent[["Store"
                                           ,"Month Opened"
                                           ,"City"
                                           ,"State"
                                           ]].where(RequireBackfill_MostRecent['Max Month End date']==i).dropna()   

        Data["Month End Date"]= val                
        Data["Sales"]= 0
        X.append(Data)
NewData = pd.concat(X) 
  1. 그런 다음 concat을 사용하여 NewData를 내 timeseries 데이터 프레임에 추가합니다.
FullData_List = [MonthlyData,NewData]
FullData=pd.concat(FullData_List)

이 전체 프로세스가 작동하지만이를 수행하는 훨씬 더 효율적인 방법이 있습니까? 더 큰 데이터로 작업을 시작하면 비용이 많이들 수 있습니다.

답변

Ferris Dec 31 2020 at 14:08
  1. upsampleDateTime 인덱스를 사용해보십시오 . 참조 : pandas-resample-upsample-last-date-edge-of-data
# group by `Store`
# with `Month End Date` column show be converted to DateTime

group.set_index(['Month End Date']).resample('M').asfreq()
  1. 주의 할 점 : 7/30/20207 월 말이 아닙니다. 7/31/2020이다. 따라서이 방법 7/30/2020을 사용 하는 것은 문제가 될 것입니다 (월 종료일을 진정한 종료일로 변환).
JoeFerndz Dec 31 2020 at 16:14

이를위한 단계별 접근 방식은 다음과 같습니다. 질문이 있으면 알려주세요.

import pandas as pd
pd.set_option('display.max_columns', None)
c = ['Store','Month Opened','State','City','Month End Date','Sales']
d = [['AAA','5/31/2020','NY','New York','5/31/2020',1000],
['AAA','5/31/2020','NY','New York','6/30/2020',5000],
['AAA','5/31/2020','NY','New York','7/30/2020',3000],
['AAA','5/31/2020','NY','New York','8/31/2020',4000],
['AAA','5/31/2020','NY','New York','9/30/2020',2000],
['BBB','6/30/2020','CT','Hartford','6/30/2020',100],
['BBB','6/30/2020','CT','Hartford','7/30/2020',200],
['CCC','3/31/2020','NJ','Cranbury','3/31/2020',1500]]

df = pd.DataFrame(d,columns = c)
df['Month Opened'] = pd.to_datetime(df['Month Opened'])
df['Month End Date'] = pd.to_datetime(df['Month End Date'])

#select last entry for each Store
df1 = df.sort_values('Month End Date').drop_duplicates('Store', keep='last').copy()

#delete all rows that have 2020-09-30. We want only ones that are less than 2020-09-30
df1 = df1[df1['Month End Date'] != '2020-09-30']

#set target end date to 2020-09-30
df1['Target_End_Date'] = pd.to_datetime ('2020-09-30')

#calculate how many rows to repeat
df1['repeats'] = df1['Target_End_Date'].dt.to_period('M').astype(int) - df1['Month End Date'].dt.to_period('M').astype(int)

#add 1 month to month end so we can start repeating from here
df1['Month End Date'] = df1['Month End Date'] + pd.DateOffset(months =1)

#set sales value as 0 per requirement
df1['Sales'] = 0

#repeat each row by the value in column repeats
df1 = df1.loc[df1.index.repeat(df1.repeats)].reset_index(drop=True)

#reset repeats to start from 0 thru n using groupby cumcouunt
#this will be used to calculate months to increment from month end date
df1['repeats'] = df1.groupby('Store').cumcount()

#update month end date based on value in repeats
df1['Month End Date'] = df1.apply(lambda x: x['Month End Date'] + pd.DateOffset(months = x['repeats']), axis=1)

#set end date to last day of the month
df1['Month End Date'] = pd.to_datetime(df1['Month End Date']) + pd.offsets.MonthEnd(0)

#drop columns that we don't need anymore. required before we concat dfs
df1.drop(columns=['Target_End_Date','repeats'],inplace=True)

#concat df and df1 to get the final dataframe
df = pd.concat([df, df1], ignore_index=True)

#sort values by Store and Month End Date
df = df.sort_values(by=['Store','Month End Date'],ignore_index=True)

print (df)

결과는 다음과 같습니다.

   Store Month Opened State      City Month End Date  Sales
0    AAA   2020-05-31    NY  New York     2020-05-31   1000
1    AAA   2020-05-31    NY  New York     2020-06-30   5000
2    AAA   2020-05-31    NY  New York     2020-07-30   3000
3    AAA   2020-05-31    NY  New York     2020-08-31   4000
4    AAA   2020-05-31    NY  New York     2020-09-30   2000
5    BBB   2020-06-30    CT  Hartford     2020-06-30    100
6    BBB   2020-06-30    CT  Hartford     2020-07-30    200
7    BBB   2020-06-30    CT  Hartford     2020-08-30      0
8    BBB   2020-06-30    CT  Hartford     2020-09-30      0
9    CCC   2020-03-31    NJ  Cranbury     2020-03-31   1500
10   CCC   2020-03-31    NJ  Cranbury     2020-04-30      0
11   CCC   2020-03-31    NJ  Cranbury     2020-05-31      0
12   CCC   2020-03-31    NJ  Cranbury     2020-06-30      0
13   CCC   2020-03-31    NJ  Cranbury     2020-07-31      0
14   CCC   2020-03-31    NJ  Cranbury     2020-08-31      0
15   CCC   2020-03-31    NJ  Cranbury     2020-09-30      0

참고 더 많은 변형을 보여주기 위해 CCC와 함께 항목을 하나 더 추가했습니다.