La mia domanda non riguarda uno specifico frammento di codice ma più generale, quindi per favore portami:python: quali sono le tecniche efficienti per trattare i dati profondamente annidati in modo flessibile?
Come dovrei organizzare i dati che sto analizzando e quali strumenti dovrei usare per gestirlo?
Sto usando python e numpy per analizzare i dati. Perché la documentazione di Python indica che i dizionari sono molto ottimizzati in Python, e anche per il fatto che i dati stessi sono molto strutturati, l'ho archiviato in un dizionario profondamente annidato.
Ecco uno scheletro del dizionario: la posizione nella gerarchia definisce la natura dell'elemento, e ogni nuova linea definisce il contenuto di una chiave nel livello precedente:
[AS091209M02] [AS091209M01] [AS090901M06] ...
[100113] [100211] [100128] [100121]
[R16] [R17] [R03] [R15] [R05] [R04] [R07] ...
[1263399103] ...
[ImageSize] [FilePath] [Trials] [Depth] [Frames] [Responses] ...
[N01] [N04] ...
[Sequential] [Randomized]
[Ch1] [Ch2]
Modifica: Per spiegare un po 'meglio i miei dati impostati:
[individual] ex: [AS091209M02]
[imaging session (date string)] ex: [100113]
[Region imaged] ex: [R16]
[timestamp of file] ex [1263399103]
[properties of file] ex: [Responses]
[regions of interest in image ] ex [N01]
[format of data] ex [Sequential]
[channel of acquisition: this key indexes an array of values] ex [Ch1]
Il tipo di operazioni che compio è, ad esempio per calcolare le proprietà delle matrici (elencati sotto Ch1, Ch2), raccogliere le matrici per fare una nuova collezione, per esempio analizzare le risposte di N01 dalla regione 16 (R16) di un dato indi in diversi punti temporali, ecc.
Questa struttura funziona bene per me ed è molto veloce, come promesso. Posso analizzare l'intero set di dati abbastanza rapidamente (e il dizionario è troppo piccolo per riempire la RAM del mio computer: mezzo concerto).
Il mio problema deriva dal modo ingombrante in cui ho bisogno di programmare le operazioni del dizionario. Ho spesso tratti di codice che vanno in questo modo:
for mk in dic.keys():
for rgk in dic[mk].keys():
for nk in dic[mk][rgk].keys():
for ik in dic[mk][rgk][nk].keys():
for ek in dic[mk][rgk][nk][ik].keys():
#do something
che è brutto, scomodo, non riutilizzabile, e fragili (necessità di ricodificare per qualsiasi variante del dizionario).
Ho provato a utilizzare le funzioni ricorsive, ma a parte le applicazioni più semplici, mi sono imbattuto in alcuni bug e comportamenti bizzarri che hanno causato una grande perdita di tempo (non aiuta che non riesca a eseguire il debug con pdb in ipython quando ho a che fare con funzioni ricorsive profondamente annidate). Alla fine l'unica funzione ricorsiva che uso regolarmente è la seguente:
def dicExplorer(dic, depth = -1, stp = 0):
'''prints the hierarchy of a dictionary.
if depth not specified, will explore all the dictionary
'''
if depth - stp == 0: return
try : list_keys = dic.keys()
except AttributeError: return
stp += 1
for key in list_keys:
else: print '+%s> [\'%s\']' %(stp * '---', key)
dicExplorer(dic[key], depth, stp)
so che sto facendo questo torto, perché il mio codice è lunga, noodly e non riutilizzabili. Devo utilizzare tecniche migliori per manipolare in modo flessibile i dizionari o per inserire i dati in qualche formato di database (sqlite?). Il mio problema è che dal momento che sono (malamente) autodidatta riguardo alla programmazione, mi manca l'esperienza pratica e le conoscenze di base per apprezzare le opzioni disponibili. Sono pronto per imparare nuovi strumenti (SQL, programmazione orientata agli oggetti), qualsiasi cosa serva per portare a termine il lavoro, ma sono riluttante a investire tempo e sforzi in qualcosa che sarà un vicolo cieco per le mie esigenze.
Quindi, quali sono i tuoi suggerimenti per affrontare questo problema ed essere in grado di codificare i miei strumenti in un modo più breve, flessibile e riutilizzabile?
Addendum: a parte di fare qualcosa con una particolare sotto-dizionario del dizionario dei dati, ecco alcuni esempi di operazioni ho implementato per la DIC dataset, o un dizionario sotto di esso:
in realtà ho un po 'ricorsivo funzioni che hanno funzionato bene:
def normalizeSeqDic(dic, norm_dic = {}, legend =()):
'''returns a normalized dictionary from a seq_amp_dic. Normalization is performed using the first time point as reference
'''
try :
list_keys = dic.keys()
for key in list_keys:
next_legend = legend + (key,)
normalizeSeqDic(dic[key], norm_dic, next_legend)
except AttributeError:
# normalization
# unpack list
mk, ek, nk, tpk = legend
#assign values to amplitude dict
if mk not in norm_dic: norm_dic[mk] = {}
if ek not in norm_dic[mk]: norm_dic[mk][ek] = {}
if nk not in norm_dic[mk][ek]: norm_dic[mk][ek][nk] = {}
if tpk not in norm_dic[mk][ek][nk]: norm_dic[mk][ek][nk][tpk] = {}
new_array = []
for x in range(dic.shape[0]):
new_array.append(dic[x][1:]/dic[x][0])
new_array = asarray(new_array)
norm_dic[mk][ek][nk][tpk] = new_array
return norm_dic
def poolDic(dic):
'''returns a dic in which all the values are pooled, and root (mk) keys are fused
these pooled dics can later be combined into another dic
'''
pooled_dic = {}
for mk in dic.keys():
for ek in dic[mk].keys():
for nk in dic[mk][ek].keys():
for tpk in dic[mk][ek][nk].keys():
#assign values to amplitude dict
if ek not in pooled_dic: pooled_dic[ek] = {}
if nk not in pooled_dic[ek]: pooled_dic[ek][nk] = {}
if tpk not in pooled_dic[ek][nk]:
pooled_dic[ek][nk][tpk] = dic[mk][ek][nk][tpk]
else: pooled_dic[ek][nk][tpk]= vstack((pooled_dic[ek][nk][tpk], dic[mk][ek][nk][tpk]))
return pooled_dic
def timePointsDic(dic):
'''Determines the timepoints for each individual key at root
'''
tp_dic = {}
for mk in dic.keys():
tp_list = []
for rgk in dic[mk].keys():
tp_list.extend(dic[mk][rgk]['Neuropil'].keys())
tp_dic[mk]=tuple(sorted(list(set(tp_list))))
return tp_dic
per alcune operazioni che ho trovato nessun altro modo se non per appiattire il dizionario:
def flattenDic(dic, label):
'''flattens a dic to produce a list of of tuples containing keys and 'label' values
'''
flat_list = []
for mk in dic.keys():
for rgk in dic[mk].keys():
for nk in dic[mk][rgk].keys():
for ik in dic[mk][rgk][nk].keys():
for ek in dic[mk][rgk][nk][ik].keys():
flat_list.append((mk, rgk, nk, ik, ek, dic[mk][rgk][nk][ik][ek][label])
return flat_list
def extractDataSequencePoints(flat_list, mk, nk, tp_list):
'''produces a list containing arrays of time point values
time_points is a list of the time points wished (can have 2 or 3 elements)
'''
nb_tp = len(tp_list)
# build tp_seq list
tp_seq = []
tp1, tp2, tp3 = [], [], []
if nk == 'Neuropil':
tp1.extend(x for x in flat_list if x[0]==mk and x[2] == 'Neuropil' and x[3] == tp_list[0])
tp2.extend(x for x in flat_list if x[0]==mk and x[2] == 'Neuropil'and x[3] == tp_list[1])
else:
tp1.extend(x for x in flat_list if x[0]==mk and x[2] != 'Neuropil'and x[3] == tp_list[0])
tp2.extend(x for x in flat_list if x[0]==mk and x[2] != 'Neuropil'and x[3] == tp_list[1])
if nb_tp == 3:
if nk == 'Neuropil':
tp3.extend(x for x in flat_list if x[0]==mk and x[2] == 'Neuropil'and x[3] == tp_list[2])
else:
tp3.extend(x for x in flat_list if x[0]==mk and x[2] != 'Neuropil'and x[3] == tp_list[2])
for x in tp1:
for y in tp2:
if x[0:3] == y[0:3] :
if nb_tp == 3:
for z in tp3:
if x[0:3] == z[0:3] :
tp_seq.append(asarray([x[4],y[4],z[4]]))
else:
tp_seq.append(asarray([x[4],y[4]]))
return tp_seq
@AlexandreS: Temo di non capire abbastanza i dati del campione per poter dare molti consigli. Per favore potresti approfondire i dati che stai analizzando e quali analisi stai eseguendo? – MattH
@MattH: ho modificato la domanda per fornire maggiori dettagli. Fammi sapere se non è sufficiente – AlexandreS
@AlexandrS: Grazie per il chiarimento. Potrebbe essere d'aiuto se potessi spiegare come vengono acquisiti/archiviati/derivati questi dati al momento. Penso che la via da seguire sarebbe per te creare un diagramma astratto strutturato come oggetti con proprietà e come gli oggetti/proprietà si relazionano l'uno all'altro. Quando deciderò come codificare una struttura dati, abbozzerò spesso queste cose. – MattH