Cómo utilizar Python para pronosticar la demanda, el tráfico y más para SEO


Ya sea que se trate de la demanda de búsqueda, los ingresos o el tráfico de la búsqueda orgánica, en algún momento de su carrera de SEO, seguramente se le pedirá que entregue un pronóstico.

En esta columna, aprenderá cómo hacerlo de manera precisa y eficiente, gracias a Python.

Vamos a explorar cómo:

  • Extraiga y grafique sus datos.
  • Utilice métodos automatizados para estimar los parámetros del modelo de mejor ajuste.
  • Aplique el método Augmented Dickey-Fuller (ADF) para probar estadísticamente una serie de tiempo.
  • Estime la cantidad de parámetros para un modelo SARIMA.
  • Pruebe sus modelos y comience a hacer pronósticos.
  • Interprete y exporte sus previsiones.

Antes de ingresar en eso, definamos los datos. Independientemente del tipo de métrica que intentemos pronosticar, esos datos ocurren a lo largo del tiempo.

En la mayoría de los casos, es probable que se trate de una serie de fechas. Entonces, efectivamente, las técnicas que estamos revelando aquí son técnicas de pronóstico de series de tiempo.

Entonces, ¿por qué Forecast?

Para responder una pregunta con una pregunta, ¿por qué no pronosticaría?

Estas técnicas se han utilizado durante mucho tiempo en la financiación de los precios de las acciones, por ejemplo, y en otros campos. ¿Por qué el SEO debería ser diferente?

Anuncio publicitario

Continuar leyendo a continuación

Con múltiples intereses, como el responsable del presupuesto y otros colegas, por ejemplo, el gerente de SEO y el director de marketing, habrá expectativas sobre lo que puede ofrecer el canal de búsqueda orgánica y si esas expectativas se cumplirán o no.

Los pronósticos brindan una respuesta basada en datos.

Información de pronóstico útil para profesionales de SEO

Adoptando el enfoque basado en datos utilizando Pitón, hay algunas cosas a tener en cuenta:

Los pronósticos funcionan mejor cuando hay muchos datos históricos.

La cadencia de los datos determinará el marco de tiempo necesario para su pronóstico.

Por ejemplo, si tiene datos diarios como los tendría en el análisis de su sitio web, entonces tendrá más de 720 puntos de datos, lo cual está bien.

Con Google Trends, que tiene una cadencia semanal, necesitará al menos 5 años para obtener 250 puntos de datos.

En cualquier caso, debe apuntar a un período de tiempo que le brinde al menos 200 puntos de datos (un número extraído de mi experiencia personal).

A los modelos les gusta la consistencia.

Si la tendencia de sus datos tiene un patrón, por ejemplo, es cíclico porque hay estacionalidad, entonces es más probable que sus pronósticos sean confiables.

Anuncio publicitario

Continuar leyendo a continuación

Por esa razón, los pronósticos no manejan muy bien las tendencias de ruptura porque no hay datos históricos en los que basar el futuro, como veremos más adelante.

Entonces, ¿cómo funcionan los modelos de pronóstico? Hay algunos aspectos que los modelos abordarán sobre los datos de series de tiempo:

Autocorrelación

La autocorrelación es la medida en que el punto de datos es similar al punto de datos anterior.

Esto puede brindarle al modelo información sobre el impacto que tiene un evento en el tiempo sobre el tráfico de búsqueda y si el patrón es estacional.

Estacionalidad

La estacionalidad informa al modelo si existe un patrón cíclico y las propiedades del patrón, por ejemplo: cuánto tiempo o el tamaño de la variación entre los máximos y mínimos.

Estacionariedad

La estacionariedad es la medida de cómo la tendencia general está cambiando con el tiempo. Una tendencia no estacionaria mostraría una tendencia general al alza o a la baja, a pesar de los altibajos de los ciclos estacionales.

Teniendo en cuenta lo anterior, los modelos «harán» cosas con los datos para que sean más una línea recta y, por lo tanto, más predecibles.

Con la teoría de la interrupción del tráfico fuera del camino, comencemos a pronosticar.

Explorando sus datos

# Import your libraries
import pandas as pd
from statsmodels.tsa.statespace.sarimax import SARIMAX
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf 
from statsmodels.tsa.seasonal import seasonal_decompose                        
from sklearn.metrics import mean_squared_error
from statsmodels.tools.eval_measures import rmse
import warnings
warnings.filterwarnings("ignore")
from pmdarima import auto_arima

Estamos usando Tendencias de Google datos, que es una exportación CSV.

Estas técnicas se pueden utilizar en cualquier dato de serie temporal, ya sea el suyo, los clics, ingresos, etc. de su cliente o empresa.

# Import Google Trends Data
df = pd.read_csv("exports/keyword_gtrends_df.csv", index_col=0)
df.head()
Datos de ejemplo de Google Trends.Captura de pantalla de Tendencias de Google, septiembre de 2021

Como era de esperar, los datos de Google Trends son una serie de tiempo muy simple con fecha, consulta y visitas que abarcan un período de 5 años.

Anuncio publicitario

Continuar leyendo a continuación

Es hora de formatear el marco de datos para que pase de largo a ancho.

Esto nos permite ver los datos con cada consulta de búsqueda como columnas:

df_unstacked = ps_trends.set_index(["date", "query"]).unstack(level=-1)
df_unstacked.columns.set_names(['hits', 'query'], inplace=True)
ps_unstacked = df_unstacked.droplevel('hits', axis=1)
ps_unstacked.columns = [c.replace(' ', '_') for c in ps_unstacked.columns]
ps_unstacked = ps_unstacked.reset_index()
ps_unstacked.head()
Marco de datos formateado.Captura de pantalla de Tendencias de Google, septiembre de 2021

Ya no tenemos una columna de hits, ya que estos son los valores de las consultas en sus respectivas columnas.

Este formato no solo es útil para SARIMA (que exploraremos aquí) sino también para redes neuronales como Long Short-term Memory (LSTM).

Anuncio publicitario

Continuar leyendo a continuación

Grafiquemos los datos:

ps_unstacked.plot(figsize=(10,5))
Trazar los datos.Captura de pantalla de Tendencias de Google, septiembre de 2021

De la trama (arriba), notarás que los perfiles de «PS4» y «PS5» son diferentes. Para los que no son jugadores entre ustedes, «PS4» es la cuarta generación de la consola Sony Playstation y «PS5» la quinta.

Las búsquedas de «PS4» son muy estacionales, ya que son un producto establecido y tienen un patrón regular aparte del final cuando surge «PS5».

Anuncio publicitario

Continuar leyendo a continuación

La “PS5” no existía hace 5 años, lo que explicaría la ausencia de una tendencia en los primeros 4 años de la trama anterior.

Elegí esas dos consultas para ayudar a ilustrar la diferencia en la efectividad de los pronósticos para las dos características muy diferentes.

Descomponiendo la tendencia

Descompongamos ahora las características estacionales (o no estacionales) de cada tendencia:

ps_unstacked.set_index("date", inplace=True)
ps_unstacked.index = pd.to_datetime(ps_unstacked.index)
query_col="ps5"

a = seasonal_decompose(ps_unstacked[query_col], model = "add")
a.plot();
Datos de series de tiempo.Captura de pantalla de Tendencias de Google, septiembre de 2021

Lo anterior muestra los datos de la serie temporal y la tendencia general suavizada que surge de 2020.

Anuncio publicitario

Continuar leyendo a continuación

El cuadro de tendencia estacional muestra picos repetidos, lo que indica que hay estacionalidad desde 2016. Sin embargo, no parece particularmente confiable dado lo plana que es la serie temporal desde 2016 hasta 2020.

También es sospechosa la falta de ruido, ya que la gráfica estacional muestra un patrón virtualmente uniforme que se repite periódicamente.

El Resid (que significa «Residual») muestra cualquier patrón de lo que queda de los datos de la serie de tiempo después de tener en cuenta la estacionalidad y la tendencia, que en efecto no es nada hasta 2020, ya que está en cero la mayor parte del tiempo.

Para «ps4»:

Datos de series de tiempo.Captura de pantalla de Tendencias de Google, septiembre de 2021

Podemos ver fluctuaciones a corto plazo (Estacionalidad) y largo plazo (Tendencia), con algo de ruido (Resid).

Anuncio publicitario

Continuar leyendo a continuación

El siguiente camino es utilizar el método Augmented Dickey-Fuller (ADF) para probar estadísticamente si una serie temporal determinada es estacionaria o no.

from pmdarima.arima import ADFTest

adf_test = ADFTest(alpha=0.05)
adf_test.should_diff(ps_unstacked[query_col])
PS4: (0.09760939899434763, True)
PS5: (0.01, False)

Podemos ver que el valor p de «PS5» que se muestra arriba es más de 0.05, lo que significa que los datos de la serie de tiempo no son estacionarios y, por lo tanto, deben diferenciarse.

«PS4», por otro lado, es menor que 0.05 a 0.01; es estacionario y no requiere diferenciación.

El objetivo de todo esto es comprender los parámetros que se utilizarían si estuviéramos construyendo manualmente un modelo para pronosticar las búsquedas de Google.

Adaptación a su modelo SARIMA

Dado que usaremos métodos automatizados para estimar los parámetros del modelo de mejor ajuste (más adelante), ahora vamos a estimar el número de parámetros para nuestro modelo SARIMA.

Elegí SARIMA porque es fácil de instalar. Aunque el Prophet de Facebook es elegante matemáticamente hablando (usa métodos Monte Carlo), no se mantiene lo suficiente y muchos usuarios pueden tener problemas al intentar instalarlo.

Anuncio publicitario

Continuar leyendo a continuación

En cualquier caso, SARIMA se compara bastante bien con Prophet en términos de precisión.

Para estimar los parámetros de nuestro modelo SARIMA, tenga en cuenta que establecemos m en 52 ya que hay 52 semanas en un año, que es la forma en que se espacian los períodos en Google Trends.

También configuramos todos los parámetros para que comiencen en 0 para que podamos dejar que auto_arima haga el trabajo soporífero y busque los valores que mejor se ajusten a los datos para el pronóstico.

ps5_s = auto_arima(ps_unstacked['ps4'],
           trace=True,
           m=52, # there are 52 periods per season (weekly data)
           start_p=0,
           start_d=0,
           start_q=0, 
           seasonal=False)

Respuesta a lo anterior:

Performing stepwise search to minimize aic

 ARIMA(3,0,3)(0,0,0)[0]             : AIC=1842.301, Time=0.26 sec
 ARIMA(0,0,0)(0,0,0)[0]             : AIC=2651.089, Time=0.01 sec
...
 ARIMA(5,0,4)(0,0,0)[0] intercept   : AIC=1829.109, Time=0.51 sec

Best model:  ARIMA(4,0,3)(0,0,0)[0] intercept
Total fit time: 6.601 seconds

La impresión de arriba muestra que los parámetros que obtienen los mejores resultados son:

PS4: ARIMA(4,0,3)(0,0,0)
PS5: ARIMA(3,1,3)(0,0,0)

La estimación de PS5 se detalla más al imprimir el resumen del modelo:

ps5_s.summary()
Resultados SARIMAX.Captura de pantalla de SARIMA, septiembre de 2021

Lo que está pasando es esto: La función busca minimizar la probabilidad de error medida por el criterio de información de Akaike (AIC) y el criterio de información bayesiano.

Anuncio publicitario

Continuar leyendo a continuación

AIC = -2Log(L) + 2(p + q + k + 1)

Tal que L es la probabilidad de los datos, k = 1 si c ≠ 0 y k = 0 si c = 0

BIC = AIC + [log(T) - 2] + (p + q + k + 1)

Al minimizar AIC y BIC, obtenemos los parámetros mejor estimados para py q.

Prueba el modelo

Ahora que tenemos los parámetros, podemos comenzar a hacer pronósticos. Primero, veremos cómo se comporta el modelo con los datos pasados. Esto nos da alguna indicación de qué tan bien podría funcionar el modelo para períodos futuros.

ps4_order = ps4_s.get_params()['order']
ps4_seasorder = ps4_s.get_params()['seasonal_order']
ps5_order = ps5_s.get_params()['order']
ps5_seasorder = ps5_s.get_params()['seasonal_order']

params = {
    "ps4": {"order": ps4_order, "seasonal_order": ps4_seasorder},
    "ps5": {"order": ps5_order, "seasonal_order": ps5_seasorder}
}

results = []
fig, axs = plt.subplots(len(X.columns), 1, figsize=(24, 12))  

for i, col in enumerate(X.columns):
    #Fit best model for each column
    arima_model = SARIMAX(train_data[col],
                          order = params[col]["order"],
                          seasonal_order = params[col]["seasonal_order"])
    arima_result = arima_model.fit()

    #Predict
    arima_pred = arima_result.predict(start = len(train_data),
                                      end = len(X)-1, typ="levels")
                             .rename("ARIMA Predictions")

    #Plot predictions
    test_data[col].plot(figsize = (8,4), legend=True, ax=axs[i])
    arima_pred.plot(legend = True, ax=axs[i])
    arima_rmse_error = rmse(test_data[col], arima_pred)

    mean_value = X[col].mean()
    results.append((col, arima_pred, arima_rmse_error, mean_value))
    print(f'Column: {col} --> RMSE Error: {arima_rmse_error} - Mean: {mean_value}n')

Column: ps4 --> RMSE Error: 8.626764032898576 - Mean: 37.83461538461538
Column: ps5 --> RMSE Error: 27.552818032476257 - Mean: 3.973076923076923

Los pronósticos muestran que los modelos son buenos cuando hay suficiente historial hasta que cambian repentinamente, como lo han hecho para PS4 a partir de marzo.

Para PS5, los modelos son prácticamente inútiles desde el principio.

Sabemos esto porque el error de raíz cuadrática media (RMSE) es 8,62 para PS4, que es más de un tercio del RMSE de PS5 de 27,5. Dado que Google Trends varía de 0 a 100, este es un margen de error del 27%.

Pronosticar el futuro

En este punto, haremos el temerario intento de pronosticar el futuro en función de los datos que tenemos hasta la fecha:

Anuncio publicitario

Continuar leyendo a continuación

oos_train_data = ps_unstacked
oos_train_data.tail()
Datos a utilizar para pronosticar.Captura de pantalla de Tendencias de Google, septiembre de 2021

Como puede ver en el extracto de la tabla anterior, ahora estamos usando todos los datos disponibles.

Ahora, predeciremos los próximos 6 meses (definidos como 26 semanas) en el siguiente código:

oos_results = []
weeks_to_predict = 26
fig, axs = plt.subplots(len(ps_unstacked.columns), 1, figsize=(24, 12)) 

for i, col in enumerate(ps_unstacked.columns):
    #Fit best model for each column
    s = auto_arima(oos_train_data[col], trace=True)
    oos_arima_model = SARIMAX(oos_train_data[col],
                          order = s.get_params()['order'],
                          seasonal_order = s.get_params()['seasonal_order'])
    oos_arima_result = oos_arima_model.fit()
    #Predict
    oos_arima_pred = oos_arima_result.predict(start = len(oos_train_data),
                                      end = len(oos_train_data) + weeks_to_predict, typ="levels").rename("ARIMA Predictions")

    #Plot predictions
    oos_arima_pred.plot(legend = True, ax=axs[i])
    axs[i].legend([col]);
    mean_value = ps_unstacked[col].mean()

    oos_results.append((col, oos_arima_pred, mean_value))
    print(f'Column: {col} - Mean: {mean_value}n')

La salida:

Performing stepwise search to minimize aic

 ARIMA(2,0,2)(0,0,0)[0] intercept   : AIC=1829.734, Time=0.21 sec
 ARIMA(0,0,0)(0,0,0)[0] intercept   : AIC=1999.661, Time=0.01 sec
...
 ARIMA(1,0,0)(0,0,0)[0]             : AIC=1865.936, Time=0.02 sec

Best model:  ARIMA(1,0,0)(0,0,0)[0] intercept
Total fit time: 0.722 seconds
Column: ps4 - Mean: 37.83461538461538
Performing stepwise search to minimize aic
 ARIMA(2,1,2)(0,0,0)[0] intercept   : AIC=1657.990, Time=0.19 sec
 ARIMA(0,1,0)(0,0,0)[0] intercept   : AIC=1696.958, Time=0.01 sec
...
 ARIMA(4,1,4)(0,0,0)[0]             : AIC=1645.756, Time=0.56 sec

Best model:  ARIMA(3,1,3)(0,0,0)[0]          
Total fit time: 7.954 seconds
Column: ps5 - Mean: 3.973076923076923

Esta vez, automatizamos la búsqueda de los mejores parámetros de ajuste y los introducimos sin rodeos en el modelo.

Ha habido muchos cambios en las últimas semanas de datos. Aunque las tendencias pronosticadas parecen probables, no parecen muy precisas, como se muestra a continuación:

Gráfico de pronóstico a partir de los datos.Captura de pantalla de Tendencias de Google, septiembre de 2021

Ese es el caso de esas dos palabras clave; si probara el código en sus otros datos basándose en consultas más establecidas, probablemente proporcionarán pronósticos más precisos sobre sus propios datos.

Anuncio publicitario

Continuar leyendo a continuación

La calidad del pronóstico dependerá de cuán estables sean los patrones históricos y obviamente no tomará en cuenta eventos imprevisibles como COVID-19.

Empiece a realizar previsiones para SEO

Si no te emocionó la herramienta de visualización de datos matplot de Python, ¡no temas! Puede exportar los datos y las previsiones a Excel, Tableau u otra interfaz de panel para que se vean mejor.

Para exportar sus pronósticos:

df_pred = pd.concat([pd.Series(res[1]) for res in oos_results], axis=1)
df_pred.columns = [x + str('_preds') for x in ps_unstacked.columns]
df_pred.to_csv('your_forecast_data.csv')

Lo que aprendimos aquí es dónde la previsión mediante modelos estadísticos es útil o es probable que agregue valor para la previsión, particularmente en sistemas automatizados como paneles, es decir, cuando hay datos históricos y no cuando hay un pico repentino, como PS5.

Más recursos:


Imagen destacada: ImageFlow / Shutterstock





Consultar el artículo en la publicación original

Cómo utilizar Python para pronosticar la demanda, el tráfico y más para SEO