Bir zaman serisi veri çerçevesi için satırlar nasıl eklenir?

Dec 31 2020

Bir zaman serisi excel dosyasını bir veri çerçevesine yükleyecek bir program yazıyorum, ardından bazı temel hesaplamaları kullanarak birkaç yeni sütun oluşturuyorum. Programım bazen bazı kayıtlar için aylar eksik olan excel dosyalarını okuyacak. Aşağıdaki örnekte iki farklı mağaza için aylık satış verilerim var. Mağazalar farklı aylarda açılır, bu nedenle ilk ay sonları farklı olacaktır. Ancak her ikisinin de 30/9/2020 tarihine kadar ay sonu verileri olması gerekir. Dosyamda, Mağaza BBB'nin 8/31/2020 ve 9/30/2020 için kayıtları yok çünkü o aylarda Satış yoktu.

Mağaza Açılan Ay Durum Kent Ay Bitiş Tarihi Satış
AAA 31.05.2020 NY New York 31.05.2020 1000
AAA 31.05.2020 NY New York 30.06.2020 5000
AAA 31.05.2020 NY New York 30.07.2020 3000
AAA 31.05.2020 NY New York 31.08.2020 4000
AAA 31.05.2020 NY New York 30.09.2020 2000
BBB 30.06.2020 CT Hartford 30.06.2020 100
BBB 30.06.2020 CT Hartford 30.07.2020 200

Dolayısıyla, bunun gibi herhangi bir durum için, 8/31 ve 9/30 için Mağaza BBB için iki satır ekleyebilmek istiyorum. Yeni satırlar, en son ay sonu tarihinden itibaren aynı Açılış Ayı, Eyalet ve Şehri kullanmalıdır. Satış, her iki yeni satır için 0 olarak ayarlanmalıdır. Şu andan itibaren aşağıdaki adımları uyguluyorum:

  1. Mağaza adı ve her Mağaza için maksimum Ay Bitiş Tarihi ve ayrıca tüm zaman serisi veri çerçevesi için maksimum Ay Bitiş Tarihi ile Veri Çerçevesi "MaxDateData" oluşturun, bu alanı "En Yakın Tarih" olarak adlandırıyorum.
Mağaza Maksimum Ay Bitiş Tarihi En Son Tarih
AAA 30.09.2020 30.09.2020
BBB 30.07.2020 30.09.2020
  1. Ana zaman serisi veri çerçevesinden en son satırı içeren "MostRecent" Dataframe'ini oluşturun. Bunu yapmak için, zaman serisi veri çerçevesi ile Mağaza Adı ve Maks Ay Bitiş Tarihindeki MaxDateData arasında bir iç birleştirme yapıyorum.
Mağaza Açılan Ay Durum Kent Ay Bitiş Tarihi Satış Maksimum Ay Bitiş Tarihi En Son Tarih
AAA 31.05.2020 NY New York 30.09.2020 2000 30.09.2020 30.09.2020
BBB 30.06.2020 CT Hartford 30.07.2020 200 30.07.2020 30.09.2020
  1. Max Ay Bitiş Tarihi <En Son Tarih olan mağazaları filtrelemek için bir where cümlesi kullanarak bir "RequireBackfill_MostRecent" veri çerçevesi oluşturun. Aşağıdaki koda bakın. Dolayısıyla bu örnekte, RequireBackfill_MostRecent tablosunda yalnızca BBB deposu için bir satır olacaktır.
RequireBackfill_Stores_MostRecent = MaxDateData.where(MaxDateData['Max Month End Date'] <MaxDateData['Most Recent Date'])
RequireBackfill_MostRecent = MostRecent.merge(RequireBackfill_Stores_MostRecent,how='inner')
  1. Daha sonra doldurmam gereken tarihler arasında geçiş yapmak için iki yuvalanmış for döngüsü kullanıyorum. Yalnızca Mağaza BBB'yi içeren RequireBackfill_MostRecent veri çerçevesinden yararlanıyor.
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. Daha sonra, concat kullanarak zaman serisi veri çerçeveme NewData ekledim
FullData_List = [MonthlyData,NewData]
FullData=pd.concat(FullData_List)

Tüm bu süreç işe yarıyor ama bunu yapmanın çok daha verimli bir yolu var mı? Daha büyük verilerle çalışmaya başladığımda bu maliyetli hale gelebilir.

Yanıtlar

Ferris Dec 31 2020 at 14:08
  1. sadece upsampleDateTime indeksini deneyin . ref: pandalar-yeniden örnekleme-örnek-son-tarih-kenar-veri
# group by `Store`
# with `Month End Date` column show be converted to DateTime

group.set_index(['Month End Date']).resample('M').asfreq()
  1. dikkat edin: 7/30/2020Temmuz ayının sonu değil. 7/31/2020dır-dir. Bu nedenle, bu yöntemi kullanmak 7/30/2020bir sorun olacaktır (Ay Bitiş Tarihini gerçekten bitiş tarihi olarak dönüştürün).
JoeFerndz Dec 31 2020 at 16:14

İşte bunu yapmak için adım adım yaklaşım. Sorularınız varsa bana bildirin.

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)

Bunun çıktısı:

   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

Not Size daha fazla varyasyon göstermek için CCC ile bir giriş daha ekledim.