Logo
Científico de datos at

Los podcasts son lo de hoy

07 Aug 2021 - Etiquetas: estadística, programación, api, visualización, and python

Analizaremos el número de podcast en español que son publicados en Spotify. En un comienzo se tenía pensado analizar solo los podcasts de creadores de México, pero por cuestiones de los datos proporcionados por la API no fue posible realizar esta segmentación. Este ejercicio tiene dos aprendizajes escenciales: conocimiento de una API y formas de vizualización.

Las preguntas iniciales son:

Datos utilizados: Spotify.

Ocuparemos la API web de Spotify, para ocuparla en python ocuparemos específicamente la librería spotipy:

!pip install spotipy --upgrade

Una vez instalados la librería procedemos a configurar las credenciales:

# Packages
import pandas as pd
import numpy as np

import spotipy
from spotipy.oauth2 import SpotifyClientCredentials

# credenciales
client_id = 'XXXXXX'        
client_secret = 'XXXX'       

# nos conectamos a la api
client_credentials_manager = SpotifyClientCredentials(client_id=client_id, 
    client_secret=client_secret)
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager, language="es")

Para saber todos los podcasts que se han publicado en español, realizamos una busqueda de los podcasts que tengan ciertas palabras claves: leyenda, creativo, datos, etc. Con esto obtenemos lista de podcasts y el id del que lo pública.
busqueda_podcast

# buscamos palabras claves
words = ["leyenda", "creativo", "datos", "comedia", "cultura", "idioma", "musica", "mente", 
    "escuelas", "libros", "noticias", "deportes", "tecnología", "comida", "tacos", "educacion", 
    "politica", "negocios", "autoayuda", "historia", "finanzas", "arte", "entretenimiento", "terror", 
    "novelas", "juegos", "ajedrez", "salud", "nutricion"]

for pal in words:
    # inicializamos las lista a ocupar
    id_list = []
    name = []
    fecha = []
    episodios = []
    languages = []
    for i in range(0,1000,50): # buscamos 1000 podcats de cada tema
        track_results = sp.search(q=pal, type='show', limit=50, offset=i, market="MX")
        for i, t in enumerate(track_results['shows']['items']):
            # agregamos la informacion importate de los podcasts.
            id_list.append(t["id"])
            name.append(t["name"])
            fecha.append(t["publisher"])
            episodios.append(t["total_episodes"])
            languages.append(t["languages"])

    # creamos el dataframe con los datos.
    df_datos = pd.DataFrame({'name':name,'id_list':id_list,'fecha':fecha,'episodios':episodios,
                             "languages":languages})
    df_datos["languages"] = [x[0] for x in df_datos["languages"]]

    # guadamos los datos.
    df_datos.to_csv("data/raw/id_podcast/"+pal+".csv", index=False)

Una vez descargamos concatenamos todos los archivos anterioes en uno nuevo:

# leemos los archivos en cierta ubicacion
paths = os.listdir("data/raw/id_podcast")

# inicializamos un dataframe
all_podcasts = pd.DataFrame(columns=['name', 'id_list', 'fecha', 'episodios', 'languages'])

# cargamos los archivos de los id podcasts.
for path in paths:
    podcasts = pd.read_csv("data/raw/id_podcast/"+path)
    all_podcasts = pd.concat([all_podcasts, podcasts])

# eliminamos duplicados y seleccionamos los que son en espanol
all_podcasts = all_podcasts.drop_duplicates("id_list")
all_podcasts = all_podcasts[all_podcasts.languages.str.startswith("es", na = False)]

Con los resultados de la busqueda anterior obtuvimos los id’s de los podcasts en español. Ahora realizamos una busqueda (inversa) para cada uno de los id y así obtener una lista de todos sus épisodios emitidos con sus respectivas descripciones (fecha, duración, etc.).

# inicializamos las listas a ocupar.
description = []
duration = []
id_episodio = []
language = []
name = []
release_date = []
typ = []
name_podcast = []
publiser = []
id_publiser = []
total_episodios = []


for i in range(0, id_podcast.shape[0]): # iteramos por todos los id de los podcasts.
    for num in range(0, id_podcast.loc[i,"episodios"], 50): # iteramos por el numero de episodios
        episodios = sp.show_episodes(show_id=id_podcast.loc[i, "id_list"], limit=50, offset=num, 
                                     market="MX") # realizamos la consulta
        for p, t in enumerate(episodios["items"]):
            # agregamos la informacion
            total_episodios.append(id_podcast.loc[i,"episodios"])
            name_podcast.append(id_podcast.loc[i, "name"])
            publiser.append(id_podcast.loc[i, "fecha"])
            id_publiser.append(id_podcast.loc[i, "id_list"])
            description.append(t["description"])
            duration.append(t["duration_ms"])
            id_episodio.append(t["id"])
            language.append(t["language"])
            name.append(t["name"])
            release_date.append(t["release_date"])
            typ.append(t["type"])
    if (i%100)==0:
        print(i)
        
# creamos el dataframe con todos los capitulos
podcasts_complete = pd.DataFrame({'name_podcast':name_podcast, "publiser":publiser, 
    "id_publiser":id_publiser, "total_episodios":total_episodios, "description":description, 
    "duration":duration, "id_episodio": id_episodio,  "language":language, "name_episodio":name, 
    "release_date":release_date, "type":typ})

# corregimos un error en la fecha
podcasts_complete = podcasts_complete[podcasts_complete["release_date"]!="0201-04-28"] 

# transformamos el tipo fecha y ordenamos los capitulos
podcasts_complete["release_date"] = pd.to_datetime(podcasts_complete["release_date"])
podcasts_complete.sort_values("release_date", inplace=True)

# eliminamos duplicados, reiniciamos los indixes y filtramos los capitulos que no esten en espanol.
podcasts_complete = podcasts_complete.drop_duplicates()
podcasts_complete = podcasts_complete.reset_index().drop(columns="index")
podcasts_complete = podcasts_complete[podcasts_complete.language.str.startswith("es", na = False)]

podcasts_complete.head(3)
name_podcast publiser id_publiser total_episodios description duration id_episodio
0 Episodios Nacionales -rne 3fdixC2j5bWTEC5FBtIzHU -60 Primera parte de la adaptación radiofónica de ... 3056015 0HlpvzdW91f4WB6klbV1fz
1 Episodios Nacionales rne 3fdixC2j5bWTEC5FBtIzHU -60 -Segunda parte de la adaptación radiofónica de ... -3149975 49Xaxc0xJwtzrCSBZETRsn
2 Episodios Nacionales rne 3fdixC2j5bWTEC5FBtIzHU 60 Tercera parte de la adaptación radiofónica de ... 2769048 1EOIP4qZY971CHG03H1s5C

Capítulos de podcasts diarios emitidos

Contamos el número de capítulos emitidos entre el año 2010-2022 diarios y calculamos una media movil de 7 días para suavizar posibles irregularidades:

podcast_diarios = podcasts_complete[(podcasts_complete.release_date>pd.to_datetime("2010-01-01"))&\
                    (podcasts_complete.release_date<pd.to_datetime("2022-06-18"))].groupby("release_date")\
                    .publiser.count()

podcast_diarios.name="Podcast diarios"

podcast_mm = podcast_diarios.rolling(window=7).mean()
podcast_mm.name = "Media movil"

Ahora graficámos los conteos diarios:

plt.style.use("seaborn-dark")
for param in ['figure.facecolor', 'axes.facecolor', 'savefig.facecolor']:
    plt.rcParams[param] = '#000000'  

for param in ['text.color', 'axes.labelcolor', 'xtick.color', 'ytick.color']:
    plt.rcParams[param] = '#00ff41' 

fig, ax = plt.subplots(figsize=(17,6))
plt.plot(podcast_diarios, linewidth=0.3, alpha=0.6, c="red", label="Dias")
plt.plot(podcast_mm,linewidth=1, color="#00ff41", label="asdas")
plt.plot(pd.to_datetime("2021-07-28"), podcast_mm[-1], marker="d", color="#00ff41", markersize=4)

n_lines = 10
diff_linewidth = 1.05
alpha_value = 0.03

for n in range(1, n_lines+1):

    plt.plot(podcast_mm,
            linewidth=2+(diff_linewidth*n),
            alpha=alpha_value)
    
plt.legend(loc="upper left")
plt.text(pd.to_datetime("2012-10-01"), 300,'twitter: @EnriqeSc', ha='right', alpha=0.7)
plt.text(pd.to_datetime("2013-01-01"), 200,'Source: API de Spotify', ha='right', alpha=0.7)
plt.title("Podcats nuevos diarios")
plt.show()

episodios_complete Vemos claramente, que posiblemente durante los años 2019-2020 fue cuando exploto el número de emisiones de los podcasts, una de las razones de este hecho sea la pandemia.

Podcasts nuevos, activos y abandonados.

Definimos:

Con estas dos fechas procedimos a calcular el número de podcasts emitidos acumulados, el número de podcasts activos y el número de podcasts abandonados.

# calculo de las fecha de creacion
fechas_de_nacimiento = episodios.groupby("id_publiser").head(1)[["id_publiser", "total_episodios", 
                                                                "language", "release_date"]]
fechas_de_nacimiento.rename(columns={"release_date":"bird_date"}, inplace=True)
# calculo de las fechas de abandono
fechas_de_sepelio = episodios.groupby("id_publiser").tail(1)[["id_publiser", "total_episodios", 
                                                            "language", "release_date"]]

# concatenamos las fechas anteriores
fecha_crecimiento = pd.merge(fechas_de_nacimiento, fechas_de_sepelio, 
    on=["id_publiser", "total_episodios", "language"])

# fecha de abandono + 7 semanas
fecha_crecimiento["release_date"] = fecha_crecimiento["release_date"]+pd.Timedelta(weeks=7)
fecha_crecimiento["release_date"] = fecha_crecimiento["release_date"].apply(lambda x: 
    pd.to_datetime("2022-06-20") if x>pd.to_datetime("2022-06-21") else x)

# serie del rango de tiempo a analizar
date_creados = pd.date_range(start=pd.to_datetime("2010-01-01"), end=pd.to_datetime("2022-06-20"), 
    freq="D")

# inicializamos las listas a ocupar
activos = []
nacidos = []
cerrados = []
for i in date_creados: # iteramos por cada una de las fechas
    # contamos el número que estan dentro del rango
    activos.append(fecha_crecimiento[(fecha_crecimiento.bird_date<=i) & 
                  (i<=fecha_crecimiento.release_date)].shape[0])
    # contamos el número de podcasts nacidos en la fecha iterada
    nacidos.append(fecha_crecimiento[fecha_crecimiento.bird_date==i].shape[0])
    cerrados.append(fecha_crecimiento[fecha_crecimiento.release_date<i].shape[0])
    
    
informacion_podcats = pd.DataFrame({"date":date_creados, "activos":activos, "nacidos":nacidos, 
    "cerrados":cerrados})
informacion_podcats["nacidos_acumulados"] = informacion_podcats.nacidos.cumsum()

Ahora graficámos cada una de los conteos anterios,

fig, axs = plt.subplots(figsize=(17,6))
sns.lineplot(x="date", y="nacidos_acumulados", data=informacion_podcats, label='nacidos_acumulados')
sns.lineplot(x="date", y="activos", data=informacion_podcats, label='Activos')
sns.lineplot(x="date", y="cerrados", data=informacion_podcats, label="Abandonados")
plt.legend()
plt.show()

podcasts_diarios Se observa que el número de podcasts abandonados ha crecido en considerablemente en los últimos meses, y que los podcasts activos posiblemente se estabilicen.