Está en la página 1de 12

Actividad 1 Técnicas de Programación

1.- Leer los datos con Python. Ficheros de navegacion y conversion

Cargar el fichero de Navegación en un data_frame_Pandas

In [ ]: import pandas as pd


import numpy as np
import re

In [ ]: df_navega = pd.read_csv("navegacion.csv", sep=";")


print(df_navega.head(),"\n"*5,df_navega.count(),"\n"*2)
#print('Informacion del df: ', df_navega.info, '\n')

print('Numero de filas y columnas que tiene: ', df_navega.shape, '\n')
print('Numero total de datos: ', df_navega.size, '\n')
print('Nombre de las columnas: ', df_navega.columns, '\n')
print('Nombre de los indices: ', df_navega.index, '\n')

Cargar el fichero de Conversión en un data_frame_Pandas

In [ ]: df_convierte = pd.read_csv("conversiones.csv", sep=";")

print(df_convierte.head())
print('Numero de filas y columnas que tiene: ', df_convierte.shape, '\n')
print('Numero total de datos: ', df_convierte.size, '\n')
print('Nombre de las columnas: ', df_convierte.columns, '\n')
print('Nombre de los indices: ', df_convierte.index, '\n')

1.b Tratamiento de datos:

Si el criterio es la velocidad de tratamiento, deberíamos eliminar todo un registro (fila) cuando algún campo esté con NaN.
Un dato que no llega completo lleva a pensar que puede estar corrupto, y por tanto ¿Cual es la validez de los campos que sí están en ese registro???
Si estamos en

Análisis Masivo de datos, no parece lógico perder el tiempo tratando datos incompletos (tenemos muchos)

Además el tratamiento hace un programa pierda velocidad mirando datos que a priori no deberían haber llegado así. Por eso yo los eliminaría en Big Data, no así bases

tradicionales donde los datos son más excasos, y no hace falta tratarlos en tiempo real y es posible mirarlos con calma y analizar con criterio. Pero aquí en Big Data los

eliminaría.

(No lo voy a hacer porque en siguientes apartados se piden opciones sin id_user o sin g_clid)(y la profesora no quiere que lo hagamos)

Por tanto cambio los NaN a campos de texto vacíos para esta práctica

In [ ]: df_navega = df_navega.fillna("")


print(df_navega.head())

2 Separar los datos en columnas campaña, adgroup, advertisement, site link

Función para filtrar las búsquedas a extraer y separar

Aplico str.split y para facilitar su entendimiento creo 1 expresion regular y 1 lista de columnas nuevas

In [ ]: # Crea un nuevo dataFrame copiando del df_navega


df_navega1 = df_navega.copy()

In [ ]: # Crea un nuevo dataFrame copiando del df_navega
#df_navega1 = df_navega.copy()

expresion=r"\/es\/|\?gclid\=|\?gclsrc\=|\?idUser\=|\&rec\=|\&adv\=|\&sl\=|\&device\=|\&adg\=|\&camp\=|https:\/www.metropolis.com\/
#expresion=r"\/es\/|\?gclid\=|\&rec\=|\&adv\=|\&sl\=|\&device\=|\&adg\=|\&camp\=|https:\/www.metropolis.com\/"
columnas_nuevas=["web","modelo","gclid1","campaña","adgroup","device","site_link","advertisement","rec"]
df_navega1[columnas_nuevas]=df_navega1["url_landing"].str.split(pat=expresion, n =26, expand=True)
# Debe borrar un par de columnas creadas por str.split que no se van a usar
df_navega1 = df_navega1.drop(['web', 'device','gclid1'], axis = 1)

# Queda la columna rec por si se debe usar para la estadística de recurrentes
# Se Limpia el último caracter que es una ? de toda la columna rec ayudado de una expresión lambda
df_navega1['rec']=df_navega1.rec.apply(lambda x: str(x)[0:-1])
# Se Limpia posibles añadidos al coche por navegación de toda la columna modelo ayudado de str.replace y expresiones regulares
df_navega1.modelo=df_navega1.modelo.str.replace(r'\/[a-z,-]*', '')
print(df_navega1.head())

In [ ]: ​

Comentarios Punto 2

Dejo 2 columnas no pedidas, modelo y rec por si hubiera que usarlas en las preguntas finales

3 Identificar Usuarios repetidos

Comprueba si hay is_users repetidos No vacíos, luego sobre los vacío si hay gclids repetidos y finalmente si con id_user y gclid vacío encuentra uuid (cookie) repetidas
In [ ]: # Repetidos, cuando existe id_user
serie3=df_navega1[df_navega1['id_user']!=""].groupby(df_navega1[df_navega1['id_user']!=""]['id_user'].tolist()).size()

#print("\n","*"*8,"Analizar Repetidos si id_user tiene información ","*"*8, "\n\n", df_navega3, end="\n"*2)
print("Los id_user repetidos ordenados de mayor a menor repeticion, son: \n\n",serie3[serie3 >1].sort_values(ascending=False), "\

#repetidos, cuando id_user esta en blanco

serie4=df_navega1[df_navega1['id_user']==""].groupby(df_navega1[df_navega1['id_user']==""]['gclid'].tolist()).size()
#print("\n","*"*8,"Analizar Repetidos si id_user está vacío ","*"*8, "\n\n", df_navega4, end="\n"*2)
print("Los gclid repetidos si id_user es vacío, ordenados de mayor a menor repeticion son: \n\n",serie4[serie4 >1].sort_values(asc

#repetidos, cuando id_user y gclid estan en blanco

mask= (df_navega1['id_user']=="") & (df_navega1['gclid']=="")
serie5=df_navega1[mask].groupby(df_navega1[mask]['uuid'].tolist()).size()
#print("\n","*"*8,"Analizar Repetidos si id_user y gclid están vacíos ","*"*8, "\n\n", df_navega5, end="\n"*2)
print("Los uuid repetidos si id_user y gclid están vacío, ordenados de mayor a menor repeticion son: \n\n",serie5[serie5 >1].sort_v

Se han encontrado varios id_users repetidos, 15 veces, 12 veces, 10 veces, ....

Cálculo de repeticiones de Glid para comprobar arañas

In [ ]: # Repetidos, cuando existe id_user


#df_navega1 = df_navega.copy()
serie6=df_navega1.groupby(df_navega1['gclid'].tolist()).size()
#print("\n","*"*8,"Analizar Repetidos si id_user tiene información ","*"*8, "\n\n", df_navega3, end="\n"*2)
print("Los gclid repetidos ordenados de mayor a menor repeticion, son: \n\n",serie6[serie6 >1].sort_values(ascending=False), "\n"

In [ ]: print(df_navega1[df_navega1['gclid']=="EAIaIQobChMIwPu5t4qs3AIVAQAAAB0BAAAAEAAYACAAEgJVzfD_BwE"][['id_user','gclid']])

Hay que limpiar los datos con gclid = EAIaIQobChMIwPu5t4qs3AIVAQAAAB0BAAAAEAAYACAAEgJVzfD_BwE y 124 repeticiones y otras 35 repeteciones con valor 0, y

diferentes id_user dentro de cada grupo de ellas, esto indica que cada grupo se corresponde con una araña rastreando en cada caso
In [ ]: indices_borrar1=df_navega1[df_navega1['gclid']=="EAIaIQobChMIwPu5t4qs3AIVAQAAAB0BAAAAEAAYACAAEgJVzfD_BwE"].index
df_navega1.drop(indices_borrar1 , inplace=True)
indices_borrar2=df_navega1[df_navega1['gclid']=="0"].index
df_navega1.drop(indices_borrar2 , inplace=True)
serie6=df_navega1.groupby(df_navega1['gclid'].tolist()).size()
print("Los gclid repetidos ahora ordenados de mayor a menor repeticion, son: \n\n",serie6[serie6 >1].sort_values(ascending=False),

Borrar usuarios repetidos opción A de la profesora

Vamos a convertir ts a una cadena numérica que permita ordenar por ella

In [ ]: df= df_navega1


df['ts']=df['ts'].apply((lambda x: ''.join([str(campo.lstrip()).zfill(2) for campo in re.split(' |\.|:|-', x)])))

df1= df.sort_values(['id_user','ts'],ascending=True)
print (df1)

a.- Resetea los índices de filas para dejar el dataframe df2 ordenado en primer nivel por id_user y en segundo nivel por fechas (ts)

b.- Añade una columna contador que contiene el número de repetición de cada valor de iduser

In [ ]: df2=df1.reset_index(drop=True)
#print(df1)
df2['contador']=df2.groupby('id_user').cumcount()
print(df2)

a.- Crea un dataframe sólo con las filas cuyo valor de contador es 0 que son las más antiguas en fecha.

b.- Resetea los indices de ese nuevo dataframe

c.- Elimina la columna 'contador' porque ya ha hecho su trabajo


In [ ]: # Filtra las lineas cuyo contador es 0, resetea el indice de ese nuevo dataframe, y al final elimina la columna contador
df3=df2[df2['contador']==0].reset_index(drop=True).drop(['contador'], axis = 1)
print (df3)

Se entra con [7109 rows x 13 columns] y se ha salido con [5643 rows x 12 columns]

Hasta aquí el tratamiento de los datos procedentes del fichero navegacion.csv

Ahora se tratarán los datos procedentes del fichero conversiones.csv almacenados en df_convierte

In [ ]: df_convierte = df_convierte.fillna("")


print(df_convierte)

Busca si hay algún registro de conversiones duplicado, iguales id_user, gclids, lead_type y result

In [ ]: df_convierte1=df_convierte.copy()
serie8=df_convierte1.groupby(df_convierte1['gclid'].tolist()).size()
print("Los gclid repetidos ordenados de mayor a menor repeticion, son: \n\n",serie8[serie8 >1].sort_values(ascending=False), "\n"

In [ ]: print(df_convierte1[df_convierte1['gclid']=="Cj0KCQjw1dGJBhD4ARIsANb6Odlnpclu0aWW8w1k4oOWd7g1IE11WEQ00IZ4fYuqMnbULg7mXXPdJmYaAhEJEA

Elimina el de fecha más reciente puesto que ya se había realizado su conversión

No voy a implementar más código para hacerlo automáticamente, pues se nos indica que hagamos análisis (humano)
Por lo tanto como sólo hay dos posiciones repetidas,

la 19 y la 26 y se nos pide borrar la más reciente, elimino la 26


In [ ]: indices_borrar3=[26]
df_convierte1.drop(index=26 , inplace=True)
df_convierte1=df_convierte1.reset_index(drop=True)

serie9=df_convierte1.groupby(df_convierte1['gclid'].tolist()).size()
print("Los gclid repetidos ahora ordenados de mayor a menor repeticion, son: \n\n",serie9[serie9 >1].sort_values(ascending=False),

In [ ]: print(df_convierte1)

Ahora quedan 27 filas, es decir ha eliminado la posición 26 completa y se ha reseteado el índice de filas

Nuevamente indico que no voy a tratar los None porque así lo indica la profesora

Creo de verdad que datos incompletos pueden indicar registro corrupto y por tanto datos no válidos, pero..

4 Unir los datos ya tratados de navegación y de conversiones

Crear una columna indicando si el usuario ha convertido o No ha convertido. Unión a través de id_user

In [ ]: dfTotal = df3.merge(df_convierte1, how = 'outer', on = ['id_user'])

In [ ]: print(df3.shape,df_convierte1.shape, dfTotal.shape)

La unión está correcta puesto que hay 13 registros de los (28-1) de conversión que tienen id_user y gclid en blanco.

Por ello No es posible asociarlos a ninguna cookie pues los uuid de navegación y los id_lead de conversión no están relacionados.

Por ello pasamos de los 5643 registros de navegación limpia a 5656 (5643 + 13) en el total

In [ ]: print (dfTotal[dfTotal.result.notnull()].count())


Exportamos el resultado a CSV compatible con Excel, separadores ;

In [ ]: dfTotal.to_csv('Informe1_todo.csv', sep=';',index=False)

Preguntas a responder

1.- ¿Cuántas visitas recibe en el día el cliente?

Como previamente se han eliminado duplicados (ha sido mi elección), entonces entiendo que cada entrada con ts es una visita.

Voy a filtrar sólo las del día 6 de Septiembre de 2021


No serán visitas aquellos registros que figuren sin ts, pueden ser conversiones, pero No visitas (aunque dada la

proporción entre navegación y conversión, no creo que vaya a cambiar mucho el porcentaje.

In [ ]: visitas6 = dfTotal[ (dfTotal["ts"] <"20210907000000") & (dfTotal["ts"] >"20210905000000") ]['ts'].count()


print("El número de visitas el 6 de septiembre: ", visitas6)

1.a.- ¿Cuántas covierten y cuántas no? en %

Todas las que aparecen se las vamos a imputar a visitas del día 6, aunque en algunas no hay enlace claro.

In [ ]: positivas= dfTotal[dfTotal["result"]=="Positivo"]['result'].count()


print ("Nº de conversiones Positivas: ",positivas,end='\n')

In [ ]: print ("En porcentaje, la relación de visitas y conversiones es de: ", positivas * 100 /visitas6)

Conclusión: Realmente parece que se puede expresar en tanto por mil, como un 1 por mil

Y las que No, pues serán del 999 por mil. Es decir del 99.9% no se convierten

Puede parecer exagerado pero No lo es porque hablamos de coches, las páginas se visitan mucho, pero su compra es una inversión

2.- Por tipo de conversión (Call, Form). ¿Cuántas hay de cada una?
Hay 27 en total, de ellas hay 19 Call y 8 en Form.

Que hayan sido positivas, es decir que se haya vendido un coche, son 6 en total, 2 desde Call y 4 desde Form

In [ ]: print ("Nº de CALLs totales: ", dfTotal[dfTotal["lead_type"]=="CALL"]['lead_type'].count(),end='\n')


print ("Nº de FORMS totales: ", dfTotal[dfTotal["lead_type"]=="FORM"]['lead_type'].count(),end='\n')

In [ ]: print ("Nº de CALLs con conversión Positiva: ", dfTotal[(dfTotal["lead_type"]=="CALL") & (dfTotal["result"]=="Positivo")]['lead_ty
print ("Nº de FORM con conversión Positiva: ", dfTotal[(dfTotal["lead_type"]=="FORM") & (dfTotal["result"]=="Positivo")]['lead_ty

In [ ]: ​

3.- Porcentaje de recurrentes sobre el total de usuarios

Tenemos sobre un total de 5643 visitas (hay de más de 1 día), 947 recurrentes y 4696 por primera vez

El porcentaje de visitantes recurrentes ronda el: 16,78% mientras que son nuevos el 83,22% restante

In [ ]: visitas= dfTotal["ts"].count()


recurrentes_True= dfTotal[dfTotal["user_recurrent"]==1]['user_recurrent'].count()
recurrentes_False= dfTotal[dfTotal["user_recurrent"]==0]['user_recurrent'].count()
print("Total de visitantes: ",visitas,recurrentes_True,recurrentes_True*100/visitas ,recurrentes_False, recurrentes_False*100/visit

In [ ]: ​

In [ ]: ​

4.- Coche más visitado

277 cea
117 cea-e
60 cea-h
383 clin200
18 clin200n
10 clin200-electrico
289 clin400
134 clin50
3 comercial
153 dep30
40 dep30F
82 fm
14 fm-hev
311 home
107 ixs-

electrico
112 ixs-hibrido
22 k43
122 life
1206 tria
150 tria-hibrido
2 renting
3612 totales
In [ ]: modelos=["tria-hibrido","tria[^-]|^tria$","life","k43","ixs-h","ixs-e","home","fm-h","fm[^-]|^fm$","dep30F","dep30[^F]|^dep30$","co

contador_modelo = list(map(lambda x : dfTotal[dfTotal.modelo.str.contains(x, regex=True, na=False)]['modelo'].count(), modelos))

print( [listado for listado in zip(modelos, contador_modelo)])
print (max(contador_modelo))

Es el modelo TRIA, con 1206 visitas al día

¿Es el que más convierte?

Ese día, de los positivos o conversiones, sólo parecen disponibles las de 3 coches:

1 tria, 1 cea-electrico y 1 clin400

Por lo tanto parece uno de los que más convierte

In [ ]: print(dfTotal[dfTotal["result"]=="Positivo"].groupby(['modelo'])['result'].count())

5 Conversion por campañas

Ojo, en los cálculos siguientes, tenemos converiones que no están enlazadas con id_user ni gclid o cookie, por ello las partidas Nan se pueden meter en otros o tomarlas

como sitelink (es decir Nan != 0 y Nan != ""). He dejado este criterio para los cáculos
In [ ]: click_anuncio= dfTotal[((dfTotal["site_link"]=="" ) | (dfTotal["site_link"]==0 ) ) ]['site_link'].count()
print ("Nº de clicks en anuncios: ", click_anuncio)
click_site= dfTotal[((dfTotal["site_link"]!="" ) & (dfTotal["site_link"]!=0) & (dfTotal["site_link"]!="undefined" ) ) ]['site_li
print ("Nº de clicks en site: ", click_site)
click_und= dfTotal[dfTotal["site_link"]=="undefined"]['site_link'].count()
print ("Nº de clicks indefinidos: ", click_und)


sl_convert= dfTotal[((dfTotal["site_link"]!="") & (dfTotal["site_link"]!=0) ) & (dfTotal["result"]=="Positivo")]['result'].count()
print ("Nº de clicks en site link con conversión Positiva: ",sl_convert,end='\n')
anuncios_convert= dfTotal[((dfTotal["site_link"]=="" ) | (dfTotal["site_link"]=="0" ) ) & (dfTotal["result"]=="Positivo")]['r
print ("Nº de clicks en anuncio con conversión Positiva: ",anuncios_convert, end='\n')
clickes=dfTotal["site_link"].count()
print ("Nº de clicks Totales: ", clickes)

print ("% de clicks covertidos sobre anuncios: ", anuncios_convert*100/click_anuncio)
print ("% de clicks covertidos sobre site click: ", sl_convert*100/click_site)

In [ ]: informe2= dfTotal[((dfTotal["site_link"]=="") | (dfTotal["site_link"]==0 )) & (dfTotal["result"]=="Positivo")][['date','campaña','


print("Informe de Positivos con clicks desde anuncios: \n\n",informe2)
informe2_positivos.to_csv('Informe2_positivos_anuncios.csv', sep=';',index=False)

In [ ]: informe3=dfTotal[((dfTotal["site_link"]!="") & (dfTotal["site_link"]!=0 )) & (dfTotal["result"]=="Positivo")][['date','campaña','a


print("Informe de Positivos con clicks desde site: \n\n",informe3)
informe3.to_csv('Informe3_positivos_anuncios.csv', sep=';',index=False)

In [ ]: ​

In [ ]: ​

In [ ]: ​

In [ ]: ​
In [ ]: ​

También podría gustarte