2016-04-05 3 views
5

Ho un pandas.DataFrame della formaclassificare i dati per valore in panda

low_bound high_bound name 
0   10   'a' 
10   20   'b' 
20   30   'c' 
30   40   'd' 
40   50   'e' 

Ho un molto lungapandas.Series della forma:

value 
5.7 
30.4 
21 
35.1 

voglio dare a ciascun valore di la serie il suo nome corrispondente rispetto al nome_fondo low_bound/high_bound/name. Ecco il mio risultato atteso:

value   name 
5.7   'a' 
30.4   'd' 
21   'c' 
35.1   'd' 

Infatti, 5,7 nome è 'un' dal 5,7 è compreso tra 0 e 10 esclusi.

Quale sarebbe il codice più efficiente? So di poter risolvere il problema scorrendo attraverso la serie, ma forse c'è una soluzione vettoriale più veloce che mi sfugge.

Nota infine che i miei limiti possono essere personalizzati e irregolari. Qui sono regolari per il bene dell'esempio.

risposta

4

Panda ha un metodo chiamato cut che farà ciò che si vuole:

import pandas as pd 

data = [{"low": 0, "high": 10, "name": "a"}, 
     {"low": 10, "high": 20, "name": "b"}, 
     {"low": 20, "high": 30, "name": "c"}, 
     {"low": 30, "high": 40, "name": "d"}, 
     {"low": 40, "high": 50, "name": "e"},] 

myDF = pd.DataFrame(data) 

#data to be binned 
mySeries = pd.Series([5.7, 30.4, 21, 35.1]) 

#create bins from original data 
bins = list(myDF["high"]) 
bins.insert(0,0) 

print pd.cut(mySeries, bins, labels = myDF["name"]) 

Che vi darà il seguente, che è quindi possibile rimettere in qualche dataframe o comunque si vuole tenere i tuoi dati:

0 a 
1 d 
2 c 
3 d 
dtype: category 
Categories (5, object): [a < b < c < d < e] 

A seconda di come sono irregolari i cassetti (e cosa si intende esattamente per abitudine/irregolare), potrebbe essere necessario ricorrere alla ripetizione della serie. Non riesco a pensare alla parte superiore della mia testa di un builtin che gestirà questo per voi, soprattutto dato che dipende dal grado/tipo di irregolarità nei cassonetti.

Looping saggio, questo metodo funzionerà se si dispone di un limite inferiore e superiore, a prescindere dalla "regolarità":

for el in mySeries: 
    print myDF["name"][(myDF["low"] < el) & (myDF["high"] > el)] 

mi rendo conto che non si potrebbe desiderare per scorrere una serie enorme, ma almeno non stiamo indicizzando manualmente nel dataframe, il che probabilmente renderebbe le cose ancora più lente