2015-05-12 9 views
8

Vorrei combinare la funzionalità di numpycon python nativo dict, ovvero creare un array multidimensionale che può essere indicizzato con stringhe.Python come indicizzare array multidimensionale con chiave di stringa, come un dict

Per esempio, avrei potuto fare questo:

dict_2d = {'a': {'x': 1, 'y': 2}, 
      'b': {'x': 3, 'y': 4}} 
print dict_2d['a','y'] # returns 2 

So che potrei fare dict_2d['a']['x'] ma a lungo termine mi piacerebbe essere in grado di trattarli come gli array NumPy tra cui fare la moltiplicazione matrice e tale e non questo è possibile con dicts a strati.

Non è nemmeno difficile scrivere una semplice versione della classe in cui uso semplicemente la classe per convertire tutte le stringhe in indici int e quindi usare numpy ma mi piacerebbe utilizzare qualcosa che esiste già, se possibile.

Modifica: Non ho bisogno di prestazioni incredibili. Lavorerò con forse array 10x10. Il mio obiettivo è rendere la scrittura del codice semplice e robusta. Lavorare con gli array di numpy non è molto diverso rispetto alla semplice scrittura in Fortran. Ho speso abbastanza della mia vita rintracciando gli errori di indicizzazione di Fortran ...

+1

Hai davvero bisogno che i dati vengano archiviati in una struttura nidificata? Potresti semplicemente usare un dict le cui chiavi sono le tuple. – BrenBarn

+0

@BrenBarn che potrebbe usare _a sacco_della memoria – 0x539

+0

si può sempre creare una classe contenitore che sovraccarichi '__getitem__' per fare questo, al punto di non essere in grado di usare tuple come indici nei dices nidificati – 0x539

risposta

9

Si può cercare pandas, che fornisce utili tipi di dati che racchiudono array numpy, consentendo di accedere a righe e colonne per nome anziché solo per numero .

2

Cosa non mi piace dare risposte pronte - ma credo che ci sarebbe voluto molto più tempo per spiegare in inglese -

L'idea di base di prendere oggetti il ​​modo NumPy non è quello di personalizzare il metodo __getitem__ - virgola i valori separati sono presentati al metodo come tuple: tu li usi semplicemente i valori nella tupla come indici ai dizionari nidificati in sequenza.

Oltre a ciò, Python reso facile per creare equivalentes dict completamente funzionale con le classi collections.abc: se si implementa un set minimo di metodi quando inhetiring da collections[.abc].MutableMapping, tutti i comportamenti dizionario è emulato - (__getitem__, __setitem__, __delitem__, __iter__, __len__) - Quindi, è solo una questione di iterare correttamente attraverso i componenti chiave e creare nuovi dizionari vuoti per memorizzare i valori necessari.

try: 
    from collections import MutableMapping 
except ImportError: 
    # Python3 compatible import 
    from collections.abc import MutableMapping 

class NestedDict(MutableMapping): 
    def __init__(self, *args, **kw): 
     self.data = dict(*args, **kw) 

    def get_last_key_levels(self, key, create=False): 
     if not isinstance(key, tuple): 
      key = (key,) 
     current_data = self.data 
     for subkey in key: 
      previous = current_data 
      current_data = current_data[subkey] if not create else current_data.setdefault(subkey, {}) 
     return previous, current_data, subkey 

    def __getitem__(self, key): 
     previous, current_data, lastkey = self.get_last_key_levels(key) 
     return current_data 

    def __setitem__(self, key, value): 
     previous, current_data, lastkey = self.get_last_key_levels(key, True) 
     previous[lastkey] = value 

    def __delitem__(self, key): 
     previous, current_data, lastkey = self.get_last_key_levels(key) 
     del previous[lastkey] 

    def __iter__(self): 
     return iter(self.data) 

    def __len__(self): 
     return len(self.data) 

    def __repr__(self): 
     return "NestedDict({})".format(repr(self.data)) 

e sei a posto per andare:

>>> from nesteddict import NestedDict 
>>> x = NestedDict(a={}) 
NestedDict({'a': {}}) 
>>> x["a", "b"] = 10 
>>> x 
NestedDict({'a': {'b': 10}}) 
>>> x["a", "c", "e"] = 25 
>>> x 
NestedDict({'a': {'c': {'e': 25}, 'b': 10}}) 
>>> x["a", "c", "e"] 
25 
>>> 

Si prega di notare che questa è un'implementazione di alto livello, che sarà solo di lavoro, ma si avrà nessun posto vicino al livello di ottimizzazione si ottiene su NumPy con questo - al contrario. Se devi eseguire operazioni rapide sui dati in questi oggetti, potresti forse controllare "cython" - o ricorrere alla tua idea di trasporre i tasti dict su tasti nuemric e usare NumPy (quell'idea potrebbe ancora raccogliere alcune idee da questa risposta)

+1

Il suggerimento per i panda di BrenBarn fa la maggior parte di ciò che voglio, anche se non sembra consentire NestedDict ['a', 'x']. Avvolgere un sottile strato sopra i panda con '__getitem__' e' __setitem__' come hai descritto, lo metterà tutto insieme. – ericksonla

0

Utilizzare i panda Diciamo che il file è come questo:

test.csv:

Params, Val1, Val2, Val3 
Par1,23,58,412 
Par2,56,45,123 
Par3,47,89,984 

modo da poter fare qualcosa di simile in pitone:

import pandas as pd 
x = pd.read_csv('test.csv', index_col='Params') 
x['Val1']['Par3'] 
47