2013-08-01 7 views
8

Sto riscontrando un problema durante la modifica dei valori in un dataframe. Voglio anche consultare un problema che devo risolvere e il modo corretto di usare i panda per risolverlo. Apprezzerò l'aiuto su entrambi. Ho un file contenente informazioni sul grado di corrispondenza dei file audio agli altoparlanti. Il file è qualcosa del genere:Modifica dei valori in pda dati del data center senza lavoro

wave_path spk_name spk_example# score mark comments isUsed 
190 122_65_02.04.51.800.wav  idoD idoD 88 NaN  NaN  False 
191 121_110_20.17.27.400.wav idoD idoD 87 NaN  NaN  False 
192 121_111_00.34.57.300.wav idoD idoD 87 NaN  NaN  False 
193 103_31_18.59.12.800.wav  idoD idoD_0 99 HIT  VP False 
194 131_101_02.08.06.500.wav idoD idoD_0 96 HIT  VP False 

Quello che devo fare è una specie di conteggio sofisticato. Ho bisogno di raggruppare i risultati per altoparlante e calcolare per ogni altoparlante qualche calcolo. Quindi procedo con l'oratore che ha fatto il miglior calcolo per me, ma prima di procedere ho bisogno di marcare tutti i file che ho usato per il calcolo come usati, cioè cambiare il valore isUsed per ogni riga in cui appaiono (i file possono apparire più di una volta) a VERO. Quindi faccio un'altra iterazione. Calcola per ciascun altoparlante, segna i file usati e così via fino a quando non ci sono più relatori da calcolare.

Ho pensato molto a come implementare quel processo usando i panda (è abbastanza facile da implementare in Python regolare ma richiederà un sacco di cicli e strutturazione dei dati che la mia ipotesi rallenterà significativamente il processo, e anche io sto usando questo processo per imparare a conoscere le abilità dei panda più profondamente)

Sono uscito con la seguente soluzione. Come passi di preparazione, raggrupperò per nome dell'altoparlante e imposteremo il nome del file come indice dal metodo set_index. Quindi eseguirò l'iterazione sul groupbyObj e applicherò la funzione di calcolo, che restituirà l'altoparlante selezionato ei file da contrassegnare come usati.

Quindi eseguirò l'iterazione sui file e li contrassegnerò come usati (ciò sarebbe rapido e semplice poiché li ho impostati come indici in anticipo), e così via fino al termine del calcolo.

In primo luogo, non sono sicuro di questa soluzione, quindi sentitevi liberi di dirmi cosa ne pensate. Ora, ho provato l'attuazione del presente, e messo nei guai:

Per prima cosa ho indicizzato per nome del file, non è un problema qui:

In [53]: 

    marked_results['isUsed'] = False 
    ind_res = marked_results.set_index('wave_path') 
    ind_res.head() 

Out[53]: 
    spk_name spk_example# score mark comments isUsed 
    wave_path      
    103_31_18.59.12.800.wav  idoD idoD 99 HIT  VP False 
    131_101_02.08.06.500.wav  idoD idoD 99 HIT  VP False 
    144_35_22.46.38.700.wav  idoD idoD 96 HIT  VP False 
    41_09_17.10.11.700.wav  idoD idoD 93 HIT  TEST False 
    122_188_03.19.20.400.wav  idoD idoD 93 NaN  NaN  False 

Poi ho scegliere un file e controllato che ricevo le voci rilevanti a quel file:

In [54]: 

    example_file = ind_res.index[0]; 
    ind_res.ix[example_file] 

Out[54]: 
    spk_name spk_example# score mark comments isUsed 
    wave_path      
    103_31_18.59.12.800.wav idoD idoD 99 HIT  VP False 
    103_31_18.59.12.800.wav idoD idoD_0 99 HIT  VP False 
    103_31_18.59.12.800.wav idoD idoD_1 97 HIT  VP False 
    103_31_18.59.12.800.wav idoD idoD_2 95 HIT  VP False 

Ora anche qui problemi. Poi ho provato a cambiare il valore isused per quel file su True, e che dove ho ottenuto il problema:

In [56]: 

    ind_res.ix[example_file]['isUsed'] = True 
    ind_res.ix[example_file].isUsed = True 
    ind_res.ix[example_file] 
Out[56]: 
    spk_name spk_example# score mark comments isUsed 
    wave_path      
    103_31_18.59.12.800.wav idoD idoD 99 HIT  VP False 
    103_31_18.59.12.800.wav idoD idoD_0 99 HIT  VP False 
    103_31_18.59.12.800.wav idoD idoD_1 97 HIT  VP False 
    103_31_18.59.12.800.wav idoD idoD_2 95 HIT  VP False 

Quindi, si vede il problema. Niente è cambiato. Che cosa sto facendo di sbagliato? Il problema descritto sopra dovrebbe essere risolto utilizzando i panda?

E inoltre: 1. Come posso avvicinarmi a un gruppo specifico con un oggetto groupby? bcz ho pensato forse invece di impostare i file come indicizzati, raggruppandoli per un file, e usando quel gruppo obj per applicare una funzione che cambia a tutte le sue occorrenze. Ma non ho trovato un modo per avvicinarmi a un gruppo specifico e passare il nome del gruppo come parametro e chiamare applicare su tutti i gruppi e quindi agire solo su uno di essi non sembrava "giusto" per me.

Spero che non è di lunga ... :)

+0

si sta modificando una copia, il '' .ix [example_file, 'isused'] '' vedi qui: http: // pandas.pydata.org/pandas-docs/dev/indexing.html#returning-a-view-versus-a-copy – Jeff

risposta

17

indicizzazione oggetti Panda può tornare due oggetti fondamentalmente diversi: una vista o una copia.

Se mask è una fetta di base, quindi df.ix[mask] restituisce un vista di df. Le viste condividono gli stessi dati sottostanti dell'oggetto originale (df). Quindi, modificando la vista, modifica anche l'oggetto originale.

Se mask è qualcosa di più complesso, quale una sequenza arbitraria di indici, quindi df.ix[mask] restituisce una copia di alcune righe in df. La modifica della copia non ha alcun effetto sull'originale.

Nel tuo caso, poiché le righe che condividono lo stesso wave_path si verificano in posizioni arbitrarie, ind_res.ix[example_file] restituisce una copia. Così

ind_res.ix[example_file]['isUsed'] = True 

non ha alcun effetto sulla ind_res.

Invece, è possibile utilizzare

ind_res.ix[example_file, 'isUsed'] = True 

modificare ind_res. Tuttavia, vedi sotto per un suggerimento groupby che penso potrebbe essere più vicino a quello che vuoi veramente.

Jeff ha già fornito un link to the Pandas docs cui si afferma che

Le regole su quando si restituisce una vista sui dati sono completamente dipendono NumPy.

Ecco il (complicato) rules which describe when a view or copy is returned. Fondamentalmente, tuttavia, la regola è se l'indice richiede una fetta distanziata regolarmente dell'array sottostante, quindi viene restituita una vista, altrimenti viene restituita una copia (per necessità).


Ecco un semplice esempio che utilizza la slice di base. Una vista restituisce df.ix, così modificando subdf modifica df così:

import pandas as pd 
import numpy as np 

df = pd.DataFrame(np.arange(12).reshape(4,3), 
     columns=list('ABC'), index=[0,1,2,3]) 

subdf = df.ix[0] 
print(subdf.values) 
# [0 1 2] 
subdf.values[0] = 100 
print(subdf) 
# A 100 
# B  1 
# C  2 
# Name: 0, dtype: int32 

print(df)   # df is modified 
#  A B C 
# 0 100 1 2 
# 1 3 4 5 
# 2 6 7 8 
# 3 9 10 11 

Ecco un semplice esempio che utilizza "indicizzazione fantasia" (righe arbitrari selezionato). Una copia viene restituita da df.ix. Pertanto la modifica di subdf non ha effetto su df.

df = pd.DataFrame(np.arange(12).reshape(4,3), 
     columns=list('ABC'), index=[0,1,0,3]) 

subdf = df.ix[0] 
print(subdf.values) 
# [[0 1 2] 
# [6 7 8]] 

subdf.values[0] = 100 
print(subdf) 
#  A B C 
# 0 100 100 100 
# 0 6 7 8 

print(df)   # df is NOT modified 
# A B C 
# 0 0 1 2 
# 1 3 4 5 
# 0 6 7 8 
# 3 9 10 11 

comunicazione l'unica differenza tra i due esempi è che nel primo, dove viene restituita la vista, l'indice era [0,1,2,3], mentre nel secondo, dove viene restituita una copia , l'indice era [0,1,0,3].

Poiché le righe selezionate in cui l'indice è 0, nel primo esempio, possiamo farlo con una porzione di base. Nel secondo esempio, le righe in cui l'indice è uguale a 0 potrebbero apparire in posizioni arbitrarie, quindi è necessario restituire una copia.


Pur avendo ranted su circa la sottigliezza del panda/NumPy affettare, io davvero non credo che

ind_res.ix[example_file, 'isUsed'] = True 

è quello che state cercando in ultima analisi. Probabilmente si vuole fare qualcosa di più come

import pandas as pd 
import numpy as np 

df = pd.DataFrame(np.arange(12).reshape(4,3), 
        columns=list('ABC')) 
df['A'] = df['A']%2 
print(df) 
# A B C 
# 0 0 1 2 
# 1 1 4 5 
# 2 0 7 8 
# 3 1 10 11 

def calculation(grp): 
    grp['C'] = True 
    return grp 

newdf = df.groupby('A').apply(calculation) 
print(newdf) 

che produce

A B  C 
0 0 1 True 
1 1 4 True 
2 0 7 True 
3 1 10 True 
+1

Grazie per la spiegazione. Trovo abbastanza fastidioso non essere in grado di dire in anticipo se ottenere una visione o una copia in anticipo. Questo è un design scadente per i miei gusti. Per quanto riguarda il tuo ultimo suggerimento, il problema è che alcuni file appaiono in più di un gruppo. quindi ho bisogno di trovare tutte le immagini in tutti i gruppi e modificarle tutte. Invece, scelgo di indicizzare in anticipo i file e cambiare tutti gli ambiti in un colpo solo. Se pensi ancora che ci sia un modo migliore per farlo, sarò lieto di ascoltare. Per favore, dimmi anche, Posso accedere ad un gruppo in particolare con il suo nome da un oggetto groupby? Molte grazie! – idoda

+0

Il suggerimento utilizzando groupby non funziona. La colonna 'isUsed' viene modificata all'interno della funzione 'calcolo', ma il dataframe esterno non cambia. Sai perché? può essere che quel gruppo sia anche una copia del DF? @unut – idoda

+0

Il suggerimento utilizzando groupby non funziona. La colonna 'isUsed' viene modificata all'interno della funzione 'calcolo', ma il dataframe esterno non cambia. Sai perché? può essere che quel gruppo sia anche una copia del DF? – idoda

Problemi correlati