2015-03-06 4 views
8

Sto cercando di capire quando utilizzare diversi metodi di selezione in DataFrame panda. In particolare, sto cercando di accedere ai valori scalari. Spesso sento raccomandare lo ix. Ma in pandas documentation si consiglia di utilizzare at e iat per un veloce scalare valore Accesso:Valore scalare panda per ottenere e impostare: ix o iat?

Since indexing with [] must handle a lot of cases (single-label access, slicing, boolean indexing, etc.), it has a bit of overhead in order to figure out what you’re asking for. If you only want to access a scalar value, the fastest way is to use the a and iat methods, which are implemented on all of the data structures.

Quindi, vorrei presumo iat dovrebbe essere più veloce per ottenere e impostare le singole celle. Tuttavia, dopo alcuni test, abbiamo rilevato che ix sarebbe comparabile o più veloce per la lettura delle celle, mentre iat molto più veloce per l'assegnazione dei valori alle celle.

Questo comportamento è documentato ovunque? È sempre così e perché succede? Deve fare qualcosa con restituire la vista o copiare? Sarei grato se qualcuno potesse mettere in luce questa domanda e spiegare cosa è consigliato per ottenere e impostare valori di cella e perché.

Ecco alcuni test che utilizzano panda (versione 0.15.2).

Giusto per assicurarmi che questo comportamento non sia un bug di questa versione, l'ho testato anche su 0.11.0. Non fornisco i risultati, ma la tendenza è esattamente la stessa: ix being much faster for getting, and iat for setting individual cells.

import pandas as pd 
import numpy as np 

df = pd.DataFrame(np.random.rand(1000,2),columns = ['A','B']) 
idx = 0 

timeit for i in range(1000): df.ix[i,'A'] = 1 
timeit for i in range(1000): df.iat[i,idx] = 2 

>> 10 loops, best of 3: 92.6 ms per loop 
>> 10 loops, best of 3: 21.7 ms per loop 

timeit for i in range(1000): tmp = df.ix[i,'A'] 
timeit for i in range(1000): tmp = df.iat[i,idx] 

>> 100 loops, best of 3: 5.31 ms per loop 
>> 10 loops, best of 3: 19.4 ms per loop 
+0

Penso che get_value() e set_value() siano più veloci – HYRY

+0

Interessante notare le differenze relative. Usando panda 0.14.1, ottengo i seguenti risultati, rispettivamente: 1) 10 loop, meglio di 3: 108 ms per loop 2) 100 loop, meglio di 3: 12.1 ms per loop 3) 100 loop, meglio di 3: 5.55 ms per loop 4) 100 loop, meglio di 3: 9.43 ms per loop – Alexander

+0

Sembra che iat per ottenere sia migliorato significativamente nelle versioni recenti. Con i panda 0.19.1 vedo ancora ix più velocemente di iat per gli ultimi 2 tempi, ma a malapena. I risultati sopra riportati sono 5.31 contro 19.4 (nella versione 0.15.2), ma vedo 6.01 contro 7.16 (nella versione 0.19.1). – JohnE

risposta

11

Pandas fa alcune cose molto interessanti con il indexing classes. Non penso di essere in grado di descrivere un modo semplice per sapere quale usare ma posso dare qualche idea sull'implementazione.

DataFrame#ix è un _IXIndexer che non dichiara il proprio __getitem__ o __setitem__. Questi due metodi sono importanti perché controllano l'accesso ai valori con Pandas. Poiché _IXIndexer non dichiara questi metodi, vengono invece utilizzati gli super class _NDFrameIndexer.

Ulteriori operazioni di scavo sul numero __getitem__ di _NDFrameIndexer mostrano che è relativamente semplice e in alcuni casi avvolge la logica trovata in get_value. Quindi lo __getitem__ si avvicina alla velocità di get_value per alcuni scenari.

_NDFrameIndexer 's __setitem__ è una storia diversa. All'inizio sembra semplice, ma il secondo metodo che chiama è _setitem_with_indexer che svolge una notevole quantità di lavoro per la maggior parte degli scenari.

Queste informazioni suggeriscono che le chiamate per ottenere valori utilizzando ix sono limitate da get_value nel migliore dei casi e le chiamate per impostare valori utilizzando ix richiederebbero un committer principale per spiegare.

Ora, per DataFrame#iat che è un _iAtIndexer che inoltre non dichiara la propria __getitem__ o __setitem__ Perciò ricadere al suo super-classe _ScalarAccessIndexer s' attuazione.

_ScalarAccessIndexer ha un'implementazione simple __getitem__ ma richiede un ciclo per convertire la chiave nel formato corretto. Il ciclo aggiuntivo aggiunge un po 'di tempo di elaborazione extra prima di chiamare get_value.

_ScalarAccessIndexer ha anche un'implementazione abbastanza simple __setitem__ che converte la chiave richiesta dai parametri set_value prima di impostare il valore.

Queste informazioni suggeriscono che le chiamate per ottenere valori utilizzando iat sono limitate da get_value e for loop. L'impostazione dei valori con iat è limitata principalmente dalle chiamate a set_value. Quindi ottenere valori con iat ha un po 'di overhead, mentre impostarli ha un overhead più piccolo.

TL; DR

credo che si sta utilizzando la funzione di accesso corretto per un indice Int64Index sulla base della documentazione, ma non credo che significa che è il più veloce. Le migliori prestazioni si possono trovare usando get_value e set_value direttamente, ma richiedono una conoscenza approfondita del modo in cui sono implementati i DataFrames di Pandas.

Note

Vale la pena notare che la documentazione sulla Panda ricorda che get_value e set_value sono deprecati che credo voleva essere iget_value invece.

Esempi

Al fine di mostrare la differenza di prestazioni con un paio di indicizzatori (tra cui chiamando direttamente get_value e set_value) ho fatto questo script:

example.py:

import timeit 


def print_index_speed(stmnt_name, stmnt): 
    """ 
    Repeatedly run the statement provided then repeat the process and take the 
    minimum execution time. 
    """ 
    setup = """ 
import pandas as pd 
import numpy as np 

df = pd.DataFrame(np.random.rand(1000,2),columns = ['A','B']) 
idx = 0 
    """ 

    minimum_execution_time = min(
     timeit.Timer(stmnt, setup=setup).repeat(5, 10)) 

    print("{stmnt_name}: {time}".format(
     stmnt_name=stmnt_name, 
     time=round(minimum_execution_time, 5))) 

print_index_speed("set ix", "for i in range(1000): df.ix[i, 'A'] = 1") 
print_index_speed("set at", "for i in range(1000): df.at[i, 'A'] = 2") 
print_index_speed("set iat", "for i in range(1000): df.iat[i, idx] = 3") 
print_index_speed("set loc", "for i in range(1000): df.loc[i, 'A'] = 4") 
print_index_speed("set iloc", "for i in range(1000): df.iloc[i, idx] = 5") 
print_index_speed(
    "set_value scalar", 
    "for i in range(1000): df.set_value(i, idx, 6, True)") 
print_index_speed(
    "set_value label", 
    "for i in range(1000): df.set_value(i, 'A', 7, False)") 

print_index_speed("get ix", "for i in range(1000): tmp = df.ix[i, 'A']") 
print_index_speed("get at", "for i in range(1000): tmp = df.at[i, 'A']") 
print_index_speed("get iat", "for i in range(1000): tmp = df.iat[i, idx]") 
print_index_speed("get loc", "for i in range(1000): tmp = df.loc[i, 'A']") 
print_index_speed("get iloc", "for i in range(1000): tmp = df.iloc[i, idx]") 
print_index_speed(
    "get_value scalar", 
    "for i in range(1000): tmp = df.get_value(i, idx, True)") 
print_index_speed(
    "get_value label", 
    "for i in range(1000): tmp = df.get_value(i, 'A', False)") 

uscita :

set ix: 0.9918 
set at: 0.06801 
set iat: 0.08606 
set loc: 1.04173 
set iloc: 1.0021 
set_value: 0.0452 
**set_value**: 0.03516 
get ix: 0.04827 
get at: 0.06889 
get iat: 0.07813 
get loc: 0.8966 
get iloc: 0.87484 
get_value: 0.04994 
**get_value**: 0.03111 
+0

Grazie per aver approfondito i dettagli di implementazione! Informazioni molto interessanti! Sì, sembra che set_value e get_value siano i migliori. Hai ragione, la documentazione è un po 'confusa se sono ammortizzati o meno. La recente documentazione della versione panda (0.15.1) non lo menziona esplicitamente per essere deprecato, né lo fa questo documento su tutte le modifiche API: http://pandas.pydata.org/pandas-docs/dev/whatsnew.html#api -cambi Menziona esplicitamente solo iget_value. – ojy