web-dev-qa-db-fra.com

Quel est le moyen le plus efficace de parcourir des images avec des pandas?

Je souhaite effectuer mes propres opérations complexes sur des données financières dans des cadres de données de manière séquentielle.

Par exemple, j'utilise le fichier CSV MSFT suivant tiré de Yahoo Finance :

Date,Open,High,Low,Close,Volume,Adj Close
2011-10-19,27.37,27.47,27.01,27.13,42880000,27.13
2011-10-18,26.94,27.40,26.80,27.31,52487900,27.31
2011-10-17,27.11,27.42,26.85,26.98,39433400,26.98
2011-10-14,27.31,27.50,27.02,27.27,50947700,27.27

....

Je fais ensuite ce qui suit:

#!/usr/bin/env python
from pandas import *

df = read_csv('table.csv')

for i, row in enumerate(df.values):
    date = df.index[i]
    open, high, low, close, adjclose = row
    #now perform analysis on open/close based on date, etc..

Est-ce le moyen le plus efficace? Compte tenu de l’accent mis sur la vitesse dans les pandas, je suppose qu’il doit exister une fonction spéciale pour parcourir les valeurs de manière à extraire également l’indice (éventuellement au moyen d’un générateur pour optimiser la mémoire)? df.iteritems n'itère malheureusement que colonne par colonne.

299
Muppet

Les dernières versions de pandas incluent désormais une fonction intégrée permettant de parcourir les lignes.

for index, row in df.iterrows():

    # do some logic here

Ou, si vous voulez plus vite, utilisez itertuples()

Mais la suggestion de unutbu d'utiliser des fonctions numpy pour éviter d'itérer sur des lignes produira le code le plus rapide.

348
Nick Crawford

Les pandas sont basés sur les tableaux NumPy. La rapidité avec les tableaux NumPy consiste à effectuer vos opérations sur l’ensemble du tableau en une fois, jamais de rangée par rangée ni d’élément par élément.

Par exemple, si close est un tableau à 1 jour et que vous souhaitez que la variation en pourcentage sur une journée complète,

pct_change = close[1:]/close[:-1]

Ceci calcule l’ensemble du tableau des pourcentages de modifications en une seule instruction au lieu de

pct_change = []
for row in close:
    pct_change.append(...)

Essayez donc d'éviter complètement la boucle Python _ for i, row in enumerate(...), et réfléchissez à la façon d'effectuer vos calculs avec des opérations sur l'ensemble du tableau (ou du cadre de données) dans son ensemble plutôt que ligne par ligne.

149
unutbu

Comme ce qui a été mentionné précédemment, pandas object est le plus efficace lorsqu'il traite le tableau entier à la fois. Cependant, pour ceux qui ont vraiment besoin de parcourir un pandas DataFrame pour effectuer quelque chose, comme moi, j'ai trouvé au moins trois façons de le faire. J'ai fait un petit test pour voir lequel des trois prend le moins de temps.

t = pd.DataFrame({'a': range(0, 10000), 'b': range(10000, 20000)})
B = []
C = []
A = time.time()
for i,r in t.iterrows():
    C.append((r['a'], r['b']))
B.append(time.time()-A)

C = []
A = time.time()
for ir in t.itertuples():
    C.append((ir[1], ir[2]))    
B.append(time.time()-A)

C = []
A = time.time()
for r in Zip(t['a'], t['b']):
    C.append((r[0], r[1]))
B.append(time.time()-A)

print B

Résultat:

[0.5639059543609619, 0.017839908599853516, 0.005645036697387695]

Ce n'est probablement pas la meilleure façon de mesurer la consommation de temps, mais c'est rapide pour moi.

Voici quelques avantages et inconvénients à mon humble avis:

  • .iterrows (): renvoie les éléments d'index et de ligne dans des variables distinctes, mais beaucoup plus lente
  • .itertuples (): plus rapide que .iterrows (), mais renvoie l'index avec les éléments de ligne, ir [0] est l'index
  • Zip: le plus rapide, mais pas d'accès à l'index de la ligne
85
Richard Wong

Vous pouvez parcourir les lignes en transposant puis en appelant itititems:

for date, row in df.T.iteritems():
   # do some logic here

Je ne suis pas certain de l'efficacité dans ce cas. Pour obtenir les meilleures performances possibles dans un algorithme itératif, vous pouvez explorer l'écriture dans Cython , afin de pouvoir effectuer les opérations suivantes:

def my_algo(ndarray[object] dates, ndarray[float64_t] open,
            ndarray[float64_t] low, ndarray[float64_t] high,
            ndarray[float64_t] close, ndarray[float64_t] volume):
    cdef:
        Py_ssize_t i, n
        float64_t foo
    n = len(dates)

    for i from 0 <= i < n:
        foo = close[i] - open[i] # will be extremely fast

Je recommanderais d'écrire l'algorithme en pure Python d'abord, assurez-vous qu'il fonctionne et voyez à quelle vitesse il est-- s'il n'est pas assez rapide, convertissez les choses en Cython comme ceci avec un minimum de travail pour obtenir quelque chose d'aussi peu rapide comme codé à la main C/C++.

72
Wes McKinney

Vous avez trois options:

Par index (le plus simple):

>>> for index in df.index:
...     print ("df[" + str(index) + "]['B']=" + str(df['B'][index]))

Avec iterrows (le plus utilisé):

>>> for index, row in df.iterrows():
...     print ("df[" + str(index) + "]['B']=" + str(row['B']))

Avec itertuples (le plus rapide):

>>> for row in df.itertuples():
...     print ("df[" + str(row.Index) + "]['B']=" + str(row.B))

Trois options affichent quelque chose comme:

df[0]['B']=125
df[1]['B']=415
df[2]['B']=23
df[3]['B']=456
df[4]['B']=189
df[5]['B']=456
df[6]['B']=12

Source: neural-networks.io

27
Fifi

J'ai vérifié iterrows après avoir remarqué la réponse de Nick Crawford , mais j'ai constaté qu'il produisait des n-uplets (index, série). Je ne sais pas ce qui fonctionnerait le mieux pour vous, mais j'ai fini par utiliser la méthode itertuples pour mon problème, ce qui donne des tuples (index, row_value1 ...).

Il y a aussi iterkv, qui parcourt les nuplets (colonnes, séries).

25
beardc

Juste comme un petit ajout, vous pouvez également faire une application si vous avez une fonction complexe que vous appliquez à une seule colonne:

http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.apply.html

df[b] = df[a].apply(lambda col: do stuff with col here)
20
Carst

Comme @ joris a souligné, iterrows est beaucoup plus lent que itertuples et itertuples est environ 100 fois plus rapide que iterrows, et j'ai testé la vitesse de les deux méthodes dans un DataFrame avec 5027505 enregistrements, le résultat est pour iterrows, il est de 1200it/s et itertuples est de 120000it/s.

Si vous utilisez itertuples, notez que chaque élément de la boucle for est un nom nommé, donc pour obtenir la valeur dans chaque colonne, vous pouvez vous reporter à l'exemple de code suivant.

>>> df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]},
                      index=['a', 'b'])
>>> df
   col1  col2
a     1   0.1
b     2   0.2
>>> for row in df.itertuples():
...     print(row.col1, row.col2)
...
1, 0.1
2, 0.2
8
GoingMyWay

Bien sûr, le moyen le plus rapide de parcourir une trame de données est d’accéder à numpy ndarray sous-jacent soit via df.values (comme vous le faites), soit en accédant à chaque colonne séparément df.column_name.values. Puisque vous voulez aussi avoir accès à l'index, vous pouvez utiliser df.index.values pour cela.

index = df.index.values
column_of_interest1 = df.column_name1.values
...
column_of_interestk = df.column_namek.values

for i in range(df.shape[0]):
   index_value = index[i]
   ...
   column_value_k = column_of_interest_k[i]

Pas pythonique? Sûr. Mais rapide.

Si vous voulez extraire plus de jus de la boucle, vous voudrez vous pencher sur cython . Cython vous permettra de gagner énormément de temps (pensez 10x-100x). Pour des performances maximales, vérifiez vues de mémoire pour Cython .

6
Vlad

Une autre suggestion serait de combiner les calculs groupby avec les calculs vectoriels si des sous-ensembles de lignes partageaient des caractéristiques qui vous permettaient de le faire.

5
JoeCondron