2017-09-12 105 views
5

mam dataframe ANajszybsza droga do scalenia pandy dataframe na zakresach

ip_address 
0 13 
1 5 
2 20 
3 11 
.. ........ 

i inny dataframe B

lowerbound_ip_address upperbound_ip_address   country 
0 0      10        Australia 
1 11      20        China 

na podstawie tego muszę dodać kolumnę w A takie, że

ip_address country 
13   China 
5   Australia 

Mam pomysł, że powinienem napisać zdefiniować funkcję, a następnie wywołać mapę na ea ch wiersz A. Ale jak przeszukiwać każdy wiersz B dla tego. Czy istnieje lepszy sposób na zrobienie tego.

+0

są dolnymi i górnymi granicami w stałych odstępach 10? – ShreyasG

+0

@ShreyasG Nie są one niezmienione –

Odpowiedz

0

Spróbuj pd.merge_asof

df['lowerbound_ip_address']=df['ip_address'] 
pd.merge_asof(df1,df,on='lowerbound_ip_address',direction ='forward',allow_exact_matches =False) 
Out[811]: 
    lowerbound_ip_address upperbound_ip_address country ip_address 
0      0      10 Australia   5 
1      11      20  China   13 
9

Korzystając pd.IntervalIndex

In [2503]: s = pd.IntervalIndex.from_arrays(dfb.lowerbound_ip_address, 
              dfb.upperbound_ip_address, 'both') 

In [2504]: dfa.assign(country=dfb.set_index(s).loc[dfa.ip_address].country.values) 
Out[2504]: 
    ip_address country 
0   13  China 
1   5 Australia 
2   20  China 
3   11  China 

Szczegóły

In [2505]: s 
Out[2505]: 
IntervalIndex([[0, 10], [11, 20]] 
       closed='both', 
       dtype='interval[int64]') 

In [2507]: dfb.set_index(s) 
Out[2507]: 
      lowerbound_ip_address upperbound_ip_address country 
[0, 10]      0      10 Australia 
[11, 20]      11      20  China 

In [2506]: dfb.set_index(s).loc[dfa.ip_address] 
Out[2506]: 
      lowerbound_ip_address upperbound_ip_address country 
[11, 20]      11      20  China 
[0, 10]      0      10 Australia 
[11, 20]      11      20  China 
[11, 20]      11      20  China 

Konfiguracja

In [2508]: dfa 
Out[2508]: 
    ip_address 
0   13 
1   5 
2   20 
3   11 

In [2509]: dfb 
Out[2509]: 
    lowerbound_ip_address upperbound_ip_address country 
0      0      10 Australia 
1      11      20  China 
+1

To jest poprawne rozwiązanie :) – Wen

+0

fajne użycie IntervalIndex; chcesz dodać mały przykład jak to do dokumentów? – Jeff

2

IntervalIndex jest jak panda 0.20.0, a rozwiązanie @JohnGalt za jego pomocą jest doskonałe.

Przed tą wersją to rozwiązanie działałoby, które rozszerza adresy IP według kraju dla pełnego zakresu.

df_ip = pd.concat([pd.DataFrame(
    {'ip_address': range(row['lowerbound_ip_address'], row['upperbound_ip_address'] + 1), 
    'country': row['country']}) 
    for _, row in dfb.iterrows()]).set_index('ip_address') 
>>> dfa.set_index('ip_address').join(df_ip) 
       country 
ip_address   
13    China 
5   Australia 
20    China 
11    China