2015-10-29 13 views
5

Ich möchte zwei Datenrahmen basierend auf zwei Spalten zusammenführen: "Code" und "Date". Es ist einfach, Datenrahmen basierend auf "Code" zusammenzufassen, aber im Fall von "Datum" wird es schwierig - es gibt keine genaue Übereinstimmung zwischen Daten in df1 und df2. Also, ich möchte die nächsten Daten auswählen. Wie kann ich das machen?Wie zwei Datenrahmen basierend auf dem nächsten Datum zusammengeführt werden

df = df1[column_names1].merge(df2[column_names2], on='Code') 
+0

damit verbundene Frage: http://stackoverflow.com/questions/24614474/pandas-merge-on-name-and-closest-date – jakevdp

+0

Hier ist eine bessere Antwort: http://stackoverflow.com/questions/21201618/pandas-merge-match-the-nearest-time-stamp-the-series-of-timestamps – jakevdp

+0

@jakevdp: Danke, aber wie kann ich es mit der Zusammenführung von Code kombinieren? Soll ich zuerst "searchsorted" verwenden und dann "mask = idx> = 0 & ..." eingeben? –

Antwort

6

Ich glaube nicht, dass es ein schneller, einzeiliger Weg, um diese Art der Sache zu tun, aber ich glaube der beste Ansatz es auf diese Weise zu tun ist:

  1. fügen Sie eine Spalte df1 mit dem am nächsten Tag aus der entsprechenden Gruppe df2 in

  2. Anruf ein Standard-Merge auf diesen

Da die Größe Ihrer Daten zunimmt, kann diese Operation für den "nächsten Termin" ziemlich teuer werden, es sei denn, Sie tun etwas Hochentwickeltes. Ich verwende gerne den Code NearestNeighbor von scikit-learn für diese Art von Dingen.

Ich habe einen Ansatz für diese Lösung zusammengestellt, der relativ gut skalieren sollte. Zuerst haben wir ein paar einfache Daten erzeugen können:

import pandas as pd 
import numpy as np 
dates = pd.date_range('2015', periods=200, freq='D') 

rand = np.random.RandomState(42) 
i1 = np.sort(rand.permutation(np.arange(len(dates)))[:5]) 
i2 = np.sort(rand.permutation(np.arange(len(dates)))[:5]) 

df1 = pd.DataFrame({'Code': rand.randint(0, 2, 5), 
        'Date': dates[i1], 
        'val1':rand.rand(5)}) 
df2 = pd.DataFrame({'Code': rand.randint(0, 2, 5), 
        'Date': dates[i2], 
        'val2':rand.rand(5)}) 

Lassen Sie uns diese Besuche:

>>> df1 
    Code  Date  val1 
0  0 2015-01-16 0.975852 
1  0 2015-01-31 0.516300 
2  1 2015-04-06 0.322956 
3  1 2015-05-09 0.795186 
4  1 2015-06-08 0.270832 

>>> df2 
    Code  Date  val2 
0  1 2015-02-03 0.184334 
1  1 2015-04-13 0.080873 
2  0 2015-05-02 0.428314 
3  1 2015-06-26 0.688500 
4  0 2015-06-30 0.058194 

Lassen Sie uns jetzt eine apply Funktion schreiben, die eine Spalte des nächsten Datums df1 mit fügt Scikit-Learn:

from sklearn.neighbors import NearestNeighbors 

def find_nearest(group, match, groupname): 
    match = match[match[groupname] == group.name] 
    nbrs = NearestNeighbors(1).fit(match['Date'].values[:, None]) 
    dist, ind = nbrs.kneighbors(group['Date'].values[:, None]) 

    group['Date1'] = group['Date'] 
    group['Date'] = match['Date'].values[ind.ravel()] 
    return group 

df1_mod = df1.groupby('Code').apply(find_nearest, df2, 'Code') 
>>> df1_mod 
    Code  Date  val1  Date1 
0  0 2015-05-02 0.975852 2015-01-16 
1  0 2015-05-02 0.516300 2015-01-31 
2  1 2015-04-13 0.322956 2015-04-06 
3  1 2015-04-13 0.795186 2015-05-09 
4  1 2015-06-26 0.270832 2015-06-08 

Schließlich können wir diese zusammen mit einem einfachen Aufruf an pd.merge:

0 zusammenführen
>>> pd.merge(df1_mod, df2, on=['Code', 'Date']) 
    Code  Date  val1  Date1  val2 
0  0 2015-05-02 0.975852 2015-01-16 0.428314 
1  0 2015-05-02 0.516300 2015-01-31 0.428314 
2  1 2015-04-13 0.322956 2015-04-06 0.080873 
3  1 2015-04-13 0.795186 2015-05-09 0.080873 
4  1 2015-06-26 0.270832 2015-06-08 0.688500 

Beachten Sie, dass Zeilen 0 und 1 beide übereinstimmten val2; Dies wird erwartet, wenn Sie Ihre gewünschte Lösung beschreiben.

+0

Nicht im Zusammenhang mit dieser Frage, aber Ihre PYCON 2015 SKLEARN war sehr nett. Sehr geschätzt für das Teilen! – WoodChopper

+0

Ich habe ein Problem mit Daten im Format: 2015-10-19T07: 42: 00.000 Hast du eine Idee, wie sie analysiert werden, damit der Code funktioniert? –

+0

Mit '' pd.to_datetime() '' – jakevdp

0

Hier ist eine alternative Lösung:

  1. Merge auf-Code.

  2. Fügen Sie eine Datumsunterschiedsspalte nach Ihren Bedürfnissen hinzu (ich habe ABS im Beispiel unten verwendet) und sortieren Sie die Daten mit der neuen Spalte.

  3. Gruppieren Sie nach den Datensätzen des ersten Datenrahmens und für jede Gruppe einen Datensatz aus dem zweiten Datenrahmen mit dem nächsten Datum.

Code:

df = df1.reset_index()[column_names1].merge(df2[column_names2], on='Code') 
df['DateDiff'] = (df['Date1'] - df['Date2']).abs() 
df.sort_values('DateDiff').groupby('index').first().reset_index() 
Verwandte Themen