Каков наиболее эффективный способ перебора кадров данных с пандами?



Я хочу выполнять свои собственные сложные операции с финансовыми данными в кадрах данных в последовательном порядке.



например, я использую следующий файл MSFT CSV, взятый из 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

....


затем я делаю следующее:



#!/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..


заключается в том, что наиболее эффективным способом? Учитывая акцент на скорости в pandas, я бы предположил, что должна быть какая-то специальная функция для итерации значений таким образом, чтобы также получить индекс (возможно, через генератор, чтобы быть эффективной памяти)? df.iteritems к сожалению, только повторяет столбец за столбцом.

719   10  

10 ответов:

самые новые версии панд теперь включают встроенную функцию для перебора строк.

for index, row in df.iterrows():

    # do some logic here

или, если вы хотите его быстрее использовать itertuples()

но предложение unutbu использовать функции numpy, чтобы избежать итерации по строкам, создаст самый быстрый код.

панды основаны на массивах NumPy. Ключ к скорости работы с массивами NumPy-это выполнение операций над всем массивом сразу, а не по строкам или элементам.

например, если close является 1-d массив, и вы хотите, чтобы день за днем процентное изменение,

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

это вычисляет весь массив процентных изменений как один оператор, а не

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

поэтому старайтесь избегать цикла Python for i, row in enumerate(...) полностью, и подумайте о том, как выполнить ваши вычисления с операциями над всем массивом (или фреймом данных) в целом, а не по строкам.

вы можете перебирать строки, транспонируя и затем вызывая iteritems:

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

Я не уверен в эффективности в этом случае. Чтобы получить максимальную производительность в итерационном алгоритме, вы можете изучить его запись в на Cython, так что вы могли бы сделать что-то вроде:

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

Я бы рекомендовал сначала написать алгоритм на чистом Python, убедиться, что он работает и посмотреть, насколько он быстр-если он недостаточно быстр, преобразуйте вещи в Cython, как это с минимальной работой, чтобы получить что-то такое же быстрое, как ручной код C/C++.

Как и то, что было упомянуто ранее, объект pandas наиболее эффективен при обработке всего массива сразу. Однако для тех, кому действительно нужно пройти через фрейм данных pandas, чтобы выполнить что-то, как я, я нашел по крайней мере три способа сделать это. Я сделал короткий тест, чтобы увидеть, какой из трех является наименее трудоемким.

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

результат:

[0.5639059543609619, 0.017839908599853516, 0.005645036697387695]

это, вероятно, не лучший способ измерить потребление времени, но это быстро для мне.

вот некоторые плюсы и минусы ИМХО:

  • .iterrows (): возвращает элементы индекса и строки в отдельных переменных, но значительно медленнее
  • .itertuples(): быстрее, чем .iterrows (), но возвращает индекс вместе с элементами строки, ir[0] - это индекс
  • zip: самый быстрый, но нет доступа к индексу строки

Я проверил iterrows увидев Ник Кроуфорд!--5--> ответ, но обнаружил, что он дает (индекс, ряд) кортежей. Не уверен, что будет работать лучше для вас, но я в конечном итоге с помощью itertuples метод для моей задачи, которая дает (index, row_value1...) кортежи.

там же iterkv, который перебирает (столбец, ряд) кортежей.

как небольшое дополнение, вы также можете применить, если у вас есть сложная функция, которую вы применяете к одному столбцу:

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

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

у вас есть три варианта:

By индекс (простой):

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

С iterrows (наиболее часто используемые):

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

С itertuples (быстрый):

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

три варианта отображения что-то вроде:

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

источник:neural-networks.io

как @joris указано, iterrows гораздо медленнее, чем itertuples и itertuples примерно в 100 раз больше, чем iterrows, и я проверил скорость обоих методов в фрейме данных с 5027505 записями результат для iterrows, это 1200it/s, и itertuples это 120000it/С.

если вы используете itertuples, обратите внимание, что каждый элемент в цикле for является namedtuple, поэтому, чтобы получить значение в каждом столбце, вы можете обратиться к следующему примеру кода

>>> 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

другим предложением было бы объединить groupby с векторизованными вычислениями, если подмножества строк разделяют характеристики, которые позволили вам это сделать.

конечно, самый быстрый способ итерации по фрейму данных-это доступ к базовому numpy ndarray либо через df.values (Как вы делаете) или путем доступа к каждому столбцу отдельно df.column_name.values. Так как вы хотите иметь доступ к индексу тоже, вы можете использовать df.index.values для этого.

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]

Не обновления? Конечно. Но быстро.

если вы хотите выжать больше сока из петли вы захотите взглянуть на на Cython. Cython позволит вам получить огромные ускорения (думаю, 10x-100x). Для максимальной проверки производительности просмотры памяти для cython.

Comments

    Ничего не найдено.