2016-01-11 11 views
5

(o una lista di liste ... Ho appena modificato)perno dizionario irregolare delle liste in panda dataframe

Esiste un metodo di python/panda esistente per la conversione di una struttura come questa

food2 = {} 
food2["apple"] = ["fruit", "round"] 
food2["bananna"] = ["fruit", "yellow", "long"] 
food2["carrot"] = ["veg", "orange", "long"] 
food2["raddish"] = ["veg", "red"] 

in una tabella pivot come questa?

+---------+-------+-----+-------+------+--------+--------+-----+ 
|   | fruit | veg | round | long | yellow | orange | red | 
+---------+-------+-----+-------+------+--------+--------+-----+ 
| apple | 1  |  | 1  |  |  |  |  | 
+---------+-------+-----+-------+------+--------+--------+-----+ 
| bananna | 1  |  |  | 1 | 1  |  |  | 
+---------+-------+-----+-------+------+--------+--------+-----+ 
| carrot |  | 1 |  | 1 |  | 1  |  | 
+---------+-------+-----+-------+------+--------+--------+-----+ 
| raddish |  | 1 |  |  |  |  | 1 | 
+---------+-------+-----+-------+------+--------+--------+-----+ 

Ingenuamente, probabilmente mi collegherei al dizionario. Vedo come posso usare una mappa su ogni elenco interno, ma non so come unire/impilarli sul dizionario. Una volta che ho fatto unirsi a loro, ho potuto solo usare pandas.pivot_table

for key in food2: 
    attrlist = food2[key] 
    onefruit_pairs = map(lambda x: [key, x], attrlist) 
    one_fruit_frame = pd.DataFrame(onefruit_pairs, columns=['fruit', 'attr']) 
    print(one_fruit_frame) 

    fruit attr 
0 bananna fruit 
1 bananna yellow 
2 bananna long 
    fruit attr 
0 carrot  veg 
1 carrot orange 
2 carrot long 
    fruit attr 
0 apple fruit 
1 apple round 
    fruit attr 
0 raddish veg 
1 raddish red 

risposta

2

Pure pitone:

from itertools import chain 

def count(d): 
    cols = set(chain(*d.values())) 
    yield ['name'] + list(cols) 
    for row, values in d.items(): 
     yield [row] + [(col in values) for col in cols] 

Testing:

>>> food2 = {   
    "apple": ["fruit", "round"], 
    "bananna": ["fruit", "yellow", "long"], 
    "carrot": ["veg", "orange", "long"], 
    "raddish": ["veg", "red"] 
} 

>>> list(count(food2)) 
[['name', 'long', 'veg', 'fruit', 'yellow', 'orange', 'round', 'red'], 
['bananna', True, False, True, True, False, False, False], 
['carrot', True, True, False, False, True, False, False], 
['apple', False, False, True, False, False, True, False], 
['raddish', False, True, False, False, False, False, True]] 

[update]

prova

Performance:

>>> from itertools import product 
>>> labels = list("".join(_) for _ in product(*(["ABCDEF"] * 7))) 
>>> attrs = labels[:1000] 
>>> import random 
>>> sample = {} 
>>> for k in labels: 
...  sample[k] = random.sample(attrs, 5) 
>>> import time 
>>> n = time.time(); list(count(sample)); print time.time() - n                 
62.0367980003 

Ci sono voluti meno di 2 minuti, per 279936 righe per 1000 colonne sulla mia macchina occupata (molte schede cromate aperte). Fammi sapere se la performance è inaccettabile.

[update]

testare le prestazioni dall'altro risposta:

>>> n = time.time(); \ 
...  df = pd.DataFrame(dict([(k, pd.Series(v)) for k,v in sample.items()])); \ 
...  print time.time() - n 
72.0512290001 

La riga successiva (df = pd.melt(...)) stava prendendo troppo tempo così ho annullato il test. Prendi questo risultato con un pizzico di sale perché era in esecuzione su una macchina occupata.

+0

Eccellente. Hai qualche intuizione su come questo si realizzerebbe (rispetto ad alcune magie di Pandas non ancora specificate) su centinaia di migliaia di "frutti" e migliaia di attributi? –

+0

I "ha" importato itertools –

+1

Questa soluzione è ottimizzata per semplicità anziché per prestazioni. C'è molto spazio per migliorare, specialmente se si conoscono gli attributi in anticipo. Aggiornato con "importazione" mancante. –

1

Una risposta che utilizza i panda.

# Test data 
food2 = {} 
food2["apple"] = ["fruit", "round"] 
food2["bananna"] = ["fruit", "yellow", "long"] 
food2["carrot"] = ["veg", "orange", "long"] 
food2["raddish"] = ["veg", "red"] 

df = DataFrame(dict([ (k,Series(v)) for k,v in food2.items() ])) 
# pivoting to long format 
df = pd.melt(df, var_name='item', value_name='categ') 
# cross-tabulation 
df = pd.crosstab(df['item'], df['categ']) 
# sorting index, maybe not necessary  
df.sort_index(inplace=True) 
df 

categ fruit long orange red round veg yellow 
item             
apple  1  0  0 0  1 0  0 
bananna  1  1  0 0  0 0  1 
carrot  0  1  1 0  0 1  0 
raddish  0  0  0 1  0 1  0 
+0

Anche a me piace questo. Hai un refuso: cater vs. categ –

+0

Grazie, ho appena corretto l'errore di battitura. – Romain

+0

Testato con lo stesso input dall'altra risposta. Stranamente, le prestazioni non sono poi così lontane per quell'input (279936 righe per 1000 colonne, molto sparse). –