Попытка найти эффективный способ использовать цикл while в пандах, который ссылается на предыдущую строку - PullRequest
3 голосов
/ 01 октября 2019

Я хочу быстро запустить эту пользовательскую функцию для тысяч строк данных. То, как я думаю, чтобы решить эту проблему, занимает много времени.

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

Приведенный ниже код является примером того, что я пытаюсь сделатьболее эффективным. Это похоже на версию Excel здесь https://www.youtube.com/watch?v=Dt0KQg52c6c&t=274s за 4 минуты 30 секунд

Я новичок в программировании и самообучении, если кто-то может указать мне направление, которое может помочь мне придумать способчтобы вычислить это в нецикличном разнообразии, это было бы очень полезно для меня и применимо к моему будущему пониманию кодирования, спасибо!

import pandas as pd
import numpy as np
import time

start_program = time.time()

df = pd.DataFrame({'Date':['2019-09-01','2019-09-02','2019-09-03','2019-09-04','2019-09-05','2019-09-06'], 'price':[10,8,5,20,50,60]})

df['Date'] = pd.to_datetime(df["Date"])

df.set_index('Date',inplace=True)

df.insert(1,'AVG', "")

df['AVG'] = df['AVG'].apply(pd.to_numeric)

df.iloc[3, df.columns.get_loc('AVG')] = np.mean(df['price'].iloc[0:4])

def avgfunc(df,target_column,price_column,row,num_avg):
    df.iloc[row, df.columns.get_loc(target_column)] = ((df[target_column].iloc[row -1]*(num_avg - 1))+df[price_column].iloc[row])/num_avg
    return df.iloc[row, df.columns.get_loc(target_column)]

leng = len(df['price'])

i=4
while i < leng:
    avgfunc(df,'AVG','price',i,5)
    i += 1      

print(df)

end_program = time.time()
print("Total time to complete program is :", end_program - start_program)

$ python test_loop.py
        price  AVG
Date
2019-09-01     10    NaN
2019-09-02      8    NaN
2019-09-03      5    NaN
2019-09-04     20  10.75
2019-09-05     50  18.60
2019-09-06     60  26.88
Total time to complete program is : 0.03003978729248047

Ответы [ 3 ]

1 голос
/ 01 октября 2019

Вот один из способов использования numpy

ave= np.frompyfunc(lambda a,b: (a+b)/2,2,1)
v=ave.accumulate(df.price.values, dtype=np.object)
v
Out[525]: array([1, 1.5, 2.25, 3.125, 4.0625, 5.03125], dtype=object)

Или мы можем ускорить с numba

from numba import njit
@njit
def ave(x):
    total = 1
    result = []
    for y in x:
        total = (y+total)/2
        result.append(total)
    return result
ave(df.price.values)
Out[528]: [1.0, 1.5, 2.25, 3.125, 4.0625, 5.03125]
0 голосов
/ 02 октября 2019

Похоже, что для строки N вы пытаетесь вычислить среднее значение столбца, помеченного "price", по окну самого себя и по предыдущим N-1 строкам в кадре данных, начиная с N = 4, верно? Вы просто делаете это итеративным способом, строка за строкой, требуя, чтобы результат предыдущей строки информировал следующую строку.

Умно, но pandas работает довольно плохо при итерации по строкам DataFrames, поэтому этого следует избегать любой ценой. Рассматривали ли вы вычисление в расширяющемся окне, используя Series.expanding()?

df["AVG"] = df["price"].expanding(min_periods=4).mean()

Аргумент min_periods указывает ширину исходного окна. Это пропустит первые 3 строки в столбце "price", установив значения этих строк в "AVG" в NaN. Затем он вычислит среднее значение первых 4 строк в "price" и использует его для 4-го элемента "AVG", среднего значения первых 5 строк "price", и использует это значение для 5-го элемента "AVG",и т. д.

0 голосов
/ 01 октября 2019

вы также можете использовать accumulate из itertools:

from itertools import accumulate
np.fromiter(accumulate(df.price,lambda x,y: (x+y)/2),float)
 array([1.     , 1.5    , 2.25   , 3.125  , 4.0625 , 5.03125])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...