Io non credo che ci sia un rapido, una riga modo per fare questo genere di cose, ma I belive l'approccio migliore è quello di fare in questo modo:
aggiungere una colonna df1
con la data più vicina dal gruppo appropriato in df2
chiamata una fusione di serie su questi
Con l'aumentare delle dimensioni dei dati, questa operazione "data più vicina" può diventare piuttosto costosa a meno che non si faccia qualcosa di sofisticato. Mi piace usare il codice NearestNeighbor
di scikit-learn per questo genere di cose.
Ho messo insieme un approccio a quella soluzione che dovrebbe scalare relativamente bene. Prima siamo in grado di generare alcuni dati semplici:
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)})
Diamo controllare questi fuori:
>>> 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
Ora scriviamo una funzione apply
che aggiunge una colonna di date più vicine a df1
utilizzando 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
Infine, possiamo unire questi insieme con una semplice chiamata a pd.merge
:
>>> 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
Si noti che le righe 0 e 1 erano entrambe uguali allo val2
; questo è previsto dato il modo in cui hai descritto la soluzione desiderata.
domanda relativa: http://stackoverflow.com/questions/24614474/pandas-merge-on-name-and-closest-date – jakevdp
Ecco una risposta migliore: http://stackoverflow.com/questions/21201618/pandas-merge-match-the-nearest-time-stamp-the-series-of-timestamps – jakevdp
@jakevdp: Grazie, ma come posso combinarlo con l'unione per codice? Dovrei prima usare "searchsorted" e quindi inserire "mask = idx> = 0 & ..."? –