2017-05-09 4 views
2

Ich habe wie so eine Liste von Datensätzen in einem Datenrahmen unter Verwendung ableiten:Wie kann ich ein Enddatum in einem Pandas Datenrahmen loc

für

1 stehen

Die Codes in update_code:

zum Inventar Update

5: aus dem Inventar entfernt.

Date  id  amount update_code 
20170101  Apple  39   1 
20170102  Pears  21   1 
20170105  Apple  13   1 
20170227  Pears     5 

Ich bin auf der Suche nach einer Spalte mit einem Datumsbereich für jeden Datensatz erstellen. Zum Beispiel sollte die Ausgabe wie folgt aussehen:

Date   id  amount update_code end_date 
20170101  Apple  39   1  20170104 
20170102  Pears  21   1  20170226 
20170105  Apple  13   1  29990909 
20170227  Pears     5  20170227 

Jedes Datum und Aufzeichnung sollte 1 Tag vor der nächsten Änderung des Datenrahmens beenden. Die erste Aufzeichnung von "Apple" ist vom 01/01/2017 bis zum 01/04/2017, da es am 01/05/2017 einen neuen "Apple" -Rekord gibt.

Ich habe versucht, dies mit df loc, aber Probleme mit der Isolierung jeder ID.

bisher Mein Code ist folgende (die nur das Enddatum folgert, wenn die update_code 5):

def end_date(df): 
    df['end_date'] = '' 
    df.loc[df['update'].isin([5]), 'endDate'] = df.Date 
    return df 

Ich kann immer noch nicht herausfinden, wie die Folgern das Endes jeden Datensatz den anderen Teil zu tun und die Daten anfügen. Vielen Dank!

Antwort

3

Zuerst möchten Sie die Datumsspalte in datetime konvertieren und einen Index erstellen, um zwischen verschiedenen Instanzen von "Äpfel" und "Birnen" zu unterscheiden.

df.Date = pd.to_datetime(df.Date, format='%Y%m%d') 

Ich gehe davon aus, dass Ihr Datenrahmen in diese Form konvertiert werden kann.

df 
#  Date  id amount update_code 
#0 2017-01-01 Apple 39.0   1 
#1 2017-01-02 Pears 21.0   1 
#2 2017-01-05 Apple 13.0   1   
#3 2017-02-27 Pears  NaN   5   

Als nächstes Gruppe durch die das Element id, jede Gruppe in der Reihenfolge zunehmender Termine vereinbaren, verschieben sich die Termine einer Zeile zurück, und von jedem Datum 1 Tag subtrahieren:

df['end_date'] = df.groupby('id').Date.apply(lambda x: 
              x.shift(-1) - pd.Timedelta(1))\ 
           .reset_index(0)['Date'] 

Dieser Vorgang erstellt eine neue Spalte, die nur teilweise gefüllt ist:

#  Date  id amount update_code end_date 
#0 2017-01-01 Apple 39.0   1 2017-01-04 
#1 2017-01-02 Pears 21.0   1 2017-02-26 
#2 2017-01-05 Apple 13.0   1  NaT 
#3 2017-02-27 Pears  NaN   5  NaT 

Nun Enddaten für den Aktualisierungscode 5 mit den abgeleiteten Daten ersetzen:

df.loc[df.update_code==5,'end_date'] = df.Date 

#  Date  id amount update_code end_date 
#0 2017-01-01 Apple 39.0   1 2017-01-04 
#1 2017-01-02 Pears 21.0   1 2017-02-26 
#2 2017-01-05 Apple 13.0   1  NaT 
#3 2017-02-27 Pears  NaN   5 2017-02-27 

Sie können NaTs ("not-a-time" s) in der letzten Spalte mit sentinels ersetzen, wenn Sie wollen:

df.end_date.fillna(pd.to_datetime('20990909', format='%Y%m%d'), inplace=True) 
+0

Das ist perfekt, vielen Dank! – staten12

+1

Schöne Lösung ++. 'df.groupby()' sortiert Gruppenschlüssel standardmäßig, so dass ich denke, wir können es ein wenig vereinfachen: 'df.groupby ('id') .Datum.Anwendung (Lambda x: x.shift (-1) - pd .Timedelta (1)) ' – MaxU

Verwandte Themen