Применить функцию к фрейму данных Pandas

#python-3.x #pandas #pandas-datareader

#python-3.x #pandas #pandas-datareader

Вопрос:

Применить функцию к фрейму данных Pandas

У меня есть код (C01), который вычисляет скользящие средние (21 период) для данной акции (отдельного лица) на фондовой бирже (IBOV — B3-БРАЗИЛИЯ). Затем я создал цикл for, в котором он определяет, что актив находится в восходящем тренде после 6 максимумов, за которыми следуют скользящие средние (гипотеза, учитывая, что для определения этого есть больше переменных).

Однако я хочу выполнить этот цикл для более чем одного ресурса, в данном случае C02, то есть он применяет функцию в каждом столбце моего кода и возвращает только имя активов, которые находятся в восходящем тренде (в данном случае имя столбца). Я попытался превратить цикл for в функцию и применить эту функцию, используя pandas «применить» к каждому столбцу (axis = 1, я попробовал tbm axis = ‘columns’). Но у меня ошибка при создании функции. Когда я выполняю функцию с помощью apply, появляется сообщение «Ошибка значения: длины должны совпадать для сравнения». Как я могу это исправить?

Благодарен за внимание.

 import numpy as np
import pandas as pd
from pandas_datareader import data as wb
from mpl_finance import candlestick_ohlc
from pandas_datareader import data as wb
from datetime import datetime
import matplotlib.dates as mpl_dates
import matplotlib.pyplot as plt
import matplotlib.dates as mdates 

#STOCK
ativo = 'WEGE3.SA'
acao2 = ativo.upper()

#START AND END ANALYSIS
inicio = '2020-1-1'
fim = '2021-1-27'

#MAKE DATAFRAME
df00 = wb.DataReader(acao2, data_source='yahoo', start=inicio, end=fim)

df00.index.names = ['Data']
df= df00.copy(deep=True)
df['Data'] = df.index.map(mdates.date2num)

# MOVING AVERAGE
df['ema21'] = df['Close'].ewm(span=21, adjust=False).mean()
df['ema72'] = df['Close'].ewm(span=72, adjust=False).mean()

#DF PLOT
df1=df
df2=df[-120:]

#TREND RULE
alta=1
for i in range(6):
  if(df2.ema21[-i-1] < df2.ema21[-i-2]):
    alta=0

baixa=1
for i in range(6):
  if(df2.ema21[-i-1] > df2.ema21[-i-2]):
    baixa=0

if (alta==1 and baixa==0):
  a1 = ativo.upper()  ' HIGH TREND'
elif (alta==0 and baixa==1):
  a1 = ativo.upper()  ' LOW TREND!'
else:
  a1 = ativo.upper()  ' UNDEFINED'
  
#PLOT RESULTS
print("---------------------------------------") 
print(a1)
print("---------------------------------------")

ohlc = df[['Data', 'Open', 'High', 'Low', 'Close']]

f1, ax = plt.subplots(figsize=(14, 8))

# plot the candlesticks
candlestick_ohlc(ax, ohlc.values, width=.6, colorup='green', colordown='red')
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))

label_ = acao2.upper()   ' EMA26'
label_2 = acao2.upper()   ' EMA09'
ax.plot(df.index, df1['ema21'], color='black', label=label_)
ax.plot(df.index, df1['ema72'], color='blue', label=label_)

ax.grid(False)
ax.legend()
ax.grid(True)

plt.title(acao2.upper()   ' : Gráfico Diário')
plt.show(block=True)

#C02

#START/END ANALISYS
inicio = '2020-1-1'
fim = '2021-1-27'

#STOCKS
ativos = ['SAPR11.SA','WEGE3.SA']

#DATAFRAME
mydata = pd.DataFrame()
for t in ativos:
    mydata[t] = wb.DataReader(t, data_source='yahoo', start=inicio, end=fim)['Close']
df2 = mydata

#MOVING AVERAGE
df3 = df2.apply(lambda x: x.rolling(window=21).mean())

#MAKE FUNCTION
def trend(x):
  tendencia_alta=1
  for i in range(6):
    if(df3.columns[-i-1:] > df3.columns[-i-2:]):
      tendencia_alta=0

  print()
  if (alta==1 and baixa==0):
      a1 = ativo.upper()  ' HIGH TREND'
  elif (alta==0 and baixa==1):
      a1 = ativo.upper()  ' LOW TREND!'
  else:
      a1 = ativo.upper()  ' UNDEFINED'

#TRYING TO APPLY THE FUNCTION IN EVERY DF3 COLUMN
df3.apply(trend, axis=1)´´´
 

Ответ №1:

что-то вроде:

 def myfunc(x):
   #do things here where x is the group of rows sent to function
   #instead of df['column'], you'll use x['column'] 
   #because you are passing the rows into x
   return x

df.groupby('yourcolumn').apply(myfunc)