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
Penso che get_value() e set_value() siano più veloci – HYRY
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
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