Utilizamos R y aplicamos las siguiente librerías:
library(tidyverse)
library(readr)
library(dplyr)
library(ggplot2)
library(data.table)
library(lubridate)
library(generics)
library(stringi)
library(descriptr)
library(psych)
Este trabajo está realizado para el proyecto final de la certificación profesional de Google Analytics en la plataforma Coursera, pudiendo elegirse dos casos prácticos. De los dos proyectos a elegir he optado por el caso práctico 1: ¿Cómo lograr el éxito rápido de un negocio de bicicletas compartidas?
He seguido los pasos recomendados en el curso y que son: preguntar, preparar, procesar, analizar, compartir, actuar.
En este paso se define el problema que pretende resolverse para entender plenamente las expectativas de los interesados. La empresa ficticia Ciclystic tiene dos tipos de clientes: ciclistas ocasionales que pagan la bici solo en las ocasiones que las toman y ciclistas que han hecho una suscripcion anual pudiendolas tomar tanta veces como quieran durante la suscripcion. La directora de marketing cree que el éxito futuro de la empresa depende de maximizar el ńumero de suscripciones anuales.
Por tanto el problema que se plantea es entender qué diferencias existen en el uso de bicicletas Cyclistic entre los ciclistas ocasionales y los que tienen una suscripción anual. A través de este conocimiento, se diseñará una nueva estrategia de marketing para convertir los ciclistas ocasionales en suscriptores anuales.
En este paso tenemos que tener presente quienes son los interesados: los ejecutivos de Cyclistic, que deben aprobar las recomendaciones a partir del conocimiento que obtengamos. Pero tambien la directora de marketing, que es de dónde parte la solicitud de análisis.
Así pues estableceré estrategias de comunicación con estos interesados: la directora de marketing y los ejecutivos, y que ayudarán a enfocar el problema.
En resumen, las tres preguntas en concreto que guiarán el programa de marketing son:
¿En qué se diferencian los socios anuales y los ciclistas ocasionales con respecto al uso de las bicicletas de Cyclistic?
¿Por qué los ciclistas ocasionales comprarían membresías anuales de Cyclistic?
¿Cómo puede usar Cyclistic los medios digitales para influenciar a los ciclistas ocasionales a convertirse en miembros?
De estas tres preguntas, la directora de marketing me asigna, como analista de datos, la primera pregunta: ¿En qué se diferencian los socios anuales y los ciclistas ocasionales con respecto al uso de las bicicletas de Cyclistic?
Para realizar el análisis tenemos los datos históricos de los viajes de Cyclistic.
La fuente de datos es un enlace a la nube de amazon aws en donde se sencuentran múltiples ficheros en formato csv de la empresa ficticia Cyclistic. Por tanto se trata de una fuente secundaria.
Hay tres tipos de ficheros con dos diferente clases de datos:
En el primero estan los datos correspondientes a los trayectos que se realizan en las bicicletas. En el segundo, los datos correspondientes a las estaciones donde estan colocadas las bicicletas.
Para este ejercicio y tal y como se indica en las instrucciones se utilizaran los datos de los 12 últimos meses, por lo que tendremos ficheros correspondientes a los meses que van desde Diciembre 2021 a Noviembre 2022.
En primer lugar hacemos una lista de las rutas a los 12 ficheros que vamos a utilizar
list_files <- list.files("/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS",
full.names= TRUE)
list_files
## [1] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202112-divvy-tripdata.csv"
## [2] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202201-divvy-tripdata.csv"
## [3] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202202-divvy-tripdata.csv"
## [4] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202203-divvy-tripdata.csv"
## [5] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202204-divvy-tripdata.csv"
## [6] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202205-divvy-tripdata.csv"
## [7] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202206-divvy-tripdata.csv"
## [8] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202207-divvy-tripdata.csv"
## [9] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202208-divvy-tripdata.csv"
## [10] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202209-divvy-publictripdata.csv"
## [11] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202210-divvy-tripdata.csv"
## [12] "/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/202211-divvy-tripdata.csv"
Despues aplicamos la función lapply y leemos con el comando read_csv todos los ficheros indicados en las rutas anteriores para crear un marco de datos de cada fichero, añadiendo una variable mes a partir del nombre de cada fichero.Asi mismo creamos otra variable a partir de la diferencia entre el momento de partida y el momento de llegada en cada recorrido. El resultado será una lista de marcos de datos.
result <- lapply(list_files,
function(x){
df <- read_csv(x)
df$month <- x
df$month <- stri_replace_all_regex(df$month,
pattern=c('/home/miguel/R_ACTIVITIES/Caso_Práctico_Google_Analytics/DATA_12MONTHS/',
'-divvy-tripdata.csv','-divvy-publictripdata.csv'),
replacement=c('', '', '' ),
vectorize=FALSE)
df$diff <- df$ended_at - df$started_at
df$diff_double <- as.double(df$diff, units="auto")
df$diff_format <- hms::hms(seconds_to_period(df$diff))
df
}
)
El anterior proceso nos da una lista de marcos de datos correspondientes cada uno a los 12 meses que analizaremos.
class(result)
## [1] "list"
Lo que tenemos que hacer ahora con esta lista de marcos de datos es convergerlos todos en un único marco de datos, para lo cual utilizaremos el comando do.call con el cual en vez de aplicar una funcion a los elementos de una lista, lo que hacemos es incorporar una lista como argumentos de una funcion; en este caso rbind.
df <- do.call(rbind,result)
Las variables finales del marco de datos único serán:
colnames(df)
## [1] "ride_id" "rideable_type" "started_at"
## [4] "ended_at" "start_station_name" "start_station_id"
## [7] "end_station_name" "end_station_id" "start_lat"
## [10] "start_lng" "end_lat" "end_lng"
## [13] "member_casual" "month" "diff"
## [16] "diff_double" "diff_format"
En este paso de limpieza podemos comprobar como en la diferencia del tiempo de recogida de la bicicleta y el tiempo de dejarla hay valores negatios y valores que son cero, por lo que tendremos que eliminar los registros correspondientes a estos valores. Por otro lado convertiremos las variables tipo de usuario y tipo de bicicleta de carácter a factor.
df <- subset(df, !sign(df$diff_double)==-1)
df <- subset(df, !sign(df$diff_double)==0)
df$member_casual <- as.factor(df$member_casual)
df$rideable_type <- as.factor(df$rideable_type)
Con lo que pasamos al siguiente apartado que será análisis y gráficos.
Seguidamente, indicamos una primera presentación del número de registros y número y característica de variables.
# Vistazo de los datos
glimpse(df)
## Rows: 5,732,913
## Columns: 17
## $ ride_id <chr> "46F8167220E4431F", "73A77762838B32FD", "4CF4245205…
## $ rideable_type <fct> electric_bike, electric_bike, electric_bike, classi…
## $ started_at <dttm> 2021-12-07 15:06:07, 2021-12-11 03:43:29, 2021-12-…
## $ ended_at <dttm> 2021-12-07 15:13:42, 2021-12-11 04:10:23, 2021-12-…
## $ start_station_name <chr> "Laflin St & Cullerton St", "LaSalle Dr & Huron St"…
## $ start_station_id <chr> "13307", "KP1705001026", "KA1504000117", "KA1504000…
## $ end_station_name <chr> "Morgan St & Polk St", "Clarendon Ave & Leland Ave"…
## $ end_station_id <chr> "TA1307000130", "TA1307000119", "13137", "KP1705001…
## $ start_lat <dbl> 41.85483, 41.89441, 41.89936, 41.89939, 41.89558, 4…
## $ start_lng <dbl> -87.66366, -87.63233, -87.64852, -87.64854, -87.682…
## $ end_lat <dbl> 41.87197, 41.96797, 41.93758, 41.89488, 41.93125, 4…
## $ end_lng <dbl> -87.65097, -87.65000, -87.64410, -87.63233, -87.644…
## $ member_casual <fct> member, casual, member, member, member, member, mem…
## $ month <chr> "202112", "202112", "202112", "202112", "202112", "…
## $ diff <drtn> 455 secs, 1614 secs, 766 secs, 883 secs, 1216 secs…
## $ diff_double <dbl> 455, 1614, 766, 883, 1216, 567, 358, 1131, 595, 989…
## $ diff_format <time> 00:07:35, 00:26:54, 00:12:46, 00:14:43, 00:20:16, …
ds_screener(df)
## -------------------------------------------------------------------------------------------------------
## | Column Name | Data Type | Levels | Missing | Missing (%) |
## -------------------------------------------------------------------------------------------------------
## | ride_id | character | NA | 0 | 0 |
## | rideable_type | factor |classic_bike docked_bike electric_bike| 0 | 0 |
## | started_at |POSIXct, POSIXt| NA | 0 | 0 |
## | ended_at |POSIXct, POSIXt| NA | 0 | 0 |
## |start_station_name| character | NA | 854817 | 14.91 |
## | start_station_id | character | NA | 854817 | 14.91 |
## | end_station_name | character | NA | 914861 | 15.96 |
## | end_station_id | character | NA | 914861 | 15.96 |
## | start_lat | numeric | NA | 0 | 0 |
## | start_lng | numeric | NA | 0 | 0 |
## | end_lat | numeric | NA | 5874 | 0.1 |
## | end_lng | numeric | NA | 5874 | 0.1 |
## | member_casual | factor | casual member | 0 | 0 |
## | month | character | NA | 0 | 0 |
## | diff | difftime | NA | 0 | 0 |
## | diff_double | numeric | NA | 0 | 0 |
## | diff_format | hms, difftime | NA | 0 | 0 |
## -------------------------------------------------------------------------------------------------------
##
## Overall Missing Values 3551104
## Percentage of Missing Values 3.64 %
## Rows with Missing Values 1322885
## Columns With Missing Values 6
Lo que nos da 5.733.451 registros y 17 variables
Hacemos un gráfico para tener una visión general de cuantos eran ciclistas ocasionales y cuantos tenían una suscripción anual. Para ello primeramente tenemos que agrupar por meses los datos. Para ello primero convertimos el campo member_casual de character en factor y seguidamente agrupamos los datos por meses.
by_month <- df %>%
group_by(month) %>%
count(member_casual)
by_month
# Gráfico barras tipo usuario.
my_labels <- c(casual="Ocasional" , member="Suscriptor")
p <- ggplot(by_month, aes(fill=member_casual,y=n,x=month )) +
geom_bar(position="dodge", stat="identity") +
scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
theme(axis.text.x =element_text(angle=45),
plot.title=element_text(size=14,hjust=0.5))+
labs(x="Mes",y="Número de Usuarios",title="Tipo de Usuario por meses del año",
fill="Tipo de Usuario\n") +
scale_fill_brewer(labels=my_labels,palette="Set1")
p
De aqui podemos sacar ya algunas conclusiones: Entre Mayo y Septiembre
vemos como aumenta el número de personas que utilizan la bici,
coincidiendo con la mejora del tiempo. Por otro lado vemos como el
aumento es tanto de ciclistas ocasionales como de suscriptores en los
meses de verano, a diferencia del resto del año donde los suscriptores
son inmensa mayoria de los que utilizan la bici.
Ahora hacemos otro gráfico, igual que antes, pero con esta otra variable: tipo de bicicleta:
by_month_rideable_type <- df %>%
group_by(month) %>%
count(rideable_type)
by_month_rideable_type
# Gráfico barras tipo de bicicleta.
my_labels <- c(classic_bike="Bici Clásica" , docked_bike="Bici Acoplada" ,
electric_bike="Bici Eléctrica")
q <- ggplot(by_month_rideable_type, aes(fill=rideable_type,y=n,x=month )) +
geom_bar(position="dodge",stat="identity") +
scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
theme(axis.text.x =element_text(angle=45),plot.title=element_text(size=14,hjust=0.5))+
labs(x="Mes",y="Número de Usuarios",title="Tipo de Bicicleta por meses del año",
fill="Tipo de Bicicleta\n") +
scale_fill_brewer(labels=my_labels,palette="Set1")
q
Comprobamos que las bicicletas acopladas son las que menos se usan. En
cuanto a las otras dos, vemos que las bicicletas clásicas se usan mas
cuando el tiempo mejora: a partir de Mayo y hasta Julio se usan mas que
las eléctricas. El resto de los meses son las eléctricas las mas
usadas.
Aqui tenemos las primera estadística descriptiva agrupadas por meses, utilizando el paquete psych
# Estadística descriptiva.
stats_by_month <- describeBy(df$diff_double, df$month, mat = TRUE)
stats_by_month
## item group1 vars n mean sd median trimmed mad min
## X11 1 202112 1 247519 871.4834 7014.819 506 592.4485 372.1326 1
## X12 2 202201 1 103765 915.9240 10693.338 472 549.9910 329.1372 1
## X13 3 202202 1 115604 854.4562 4930.533 483 564.6887 346.9284 1
## X14 4 202203 1 284024 1109.9064 8815.417 569 687.5172 450.7104 1
## X15 5 202204 1 371218 1058.2099 7483.238 567 681.8104 452.1930 1
## X16 6 202205 1 634810 1265.9562 8169.978 694 827.1426 563.3880 1
## X17 7 202206 1 769138 1361.1041 12913.682 713 830.2816 550.0446 1
## X18 8 202207 1 823416 1283.5609 10416.728 702 824.7188 548.5620 1
## X19 9 202208 1 785855 1239.5607 11548.858 658 768.6158 504.0840 1
## X110 10 202209 1 701267 1159.6421 11354.978 613 714.4354 465.5364 1
## X111 11 202210 1 558620 1041.4853 12567.481 540 633.5952 409.1976 1
## X112 12 202211 1 337677 849.9789 7126.576 484 560.9855 349.8936 1
## max range skew kurtosis se
## X11 1824033 1824032 151.01317 30629.885 14.09978
## X12 1756266 1756265 121.51310 17640.793 33.19616
## X13 654358 654357 69.79599 6972.770 14.50132
## X14 2061244 2061243 93.50005 14134.727 16.54114
## X15 1267332 1267331 87.25183 9947.330 12.28217
## X16 2175468 2175467 107.55694 17017.174 10.25413
## X17 2149238 2149237 83.07739 8714.259 14.72475
## X18 2052529 2052528 104.12757 14535.819 11.47947
## X19 1687762 1687761 75.60856 6912.517 13.02770
## X110 1661854 1661853 76.03587 6863.359 13.55953
## X111 2483235 2483234 104.97993 13406.180 16.81473
## X112 1176756 1176755 95.89293 11410.097 12.26394
A continuación presentamos el gráfico de tiempo de recorrido medio por tipo de usuario y por mes, despues del cálculo de las estadísticas agrupadas por mes y tipo de usuario.
stats_by_month_by_membercasual <- describeBy(df$diff_double,
list(df$month, df$member_casual), mat = TRUE)
stats_by_month_by_membercasual
## item group1 group2 vars n mean sd median trimmed
## X11 1 202112 casual 1 69729 1409.8394 13002.201 657 786.8114
## X12 2 202201 casual 1 18517 1822.9426 24763.779 608 714.6115
## X13 3 202202 casual 1 21414 1602.6567 10675.242 654 789.6693
## X14 4 202203 casual 1 89874 1957.5217 15437.776 853 1046.2222
## X15 5 202204 casual 1 126398 1772.2120 12639.486 830 1010.8012
## X16 6 202205 casual 1 280387 1852.3617 12124.695 917 1118.6448
## X17 7 202206 casual 1 369022 1926.0914 18535.529 861 1027.9823
## X18 8 202207 casual 1 406013 1756.8735 14732.807 842 1018.5689
## X19 9 202208 casual 1 358886 1758.7909 16977.793 778 938.5667
## X110 10 202209 casual 1 296664 1679.2975 17318.841 722 868.3556
## X111 11 202210 casual 1 208961 1583.4578 20388.445 648 789.7917
## X112 12 202211 casual 1 100742 1278.0905 12781.044 553 662.3149
## X113 13 202112 member 1 177790 660.3409 1430.138 457 527.9456
## X114 14 202201 member 1 85248 718.9075 2401.823 449 518.7004
## X115 15 202202 member 1 94190 684.3536 1942.412 451 522.4609
## X116 16 202203 member 1 194150 717.5367 1695.979 482 562.9451
## X117 17 202204 member 1 244820 689.5780 1425.186 473 551.9011
## X118 18 202205 member 1 354423 802.0459 1663.549 563 651.6374
## X119 19 202206 member 1 400116 840.0233 1770.549 602 686.6278
## X120 20 202207 member 1 417403 823.1640 1578.996 594 678.1904
## X121 21 202208 member 1 426969 803.1252 1668.830 576 655.8921
## X122 22 202209 member 1 404603 778.6192 1790.760 546 622.9868
## X123 23 202210 member 1 349659 717.5952 1904.908 486 559.1236
## X124 24 202211 member 1 236935 667.9508 1677.898 458 524.8817
## mad min max range skew kurtosis se
## X11 489.2580 1 1824033 1824032 83.91480 9194.8140 49.239106
## X12 435.8844 1 1756266 1756265 54.60728 3426.2823 181.983333
## X13 483.3276 1 654358 654357 36.00842 1693.7523 72.950592
## X14 702.7524 1 2061244 2061243 54.75026 4734.8577 51.495313
## X15 676.0656 1 1267332 1267331 52.89721 3574.9187 35.551613
## X16 741.3000 1 2175468 2175467 74.23153 7925.9461 22.897702
## X17 667.1700 1 2149238 2149237 58.43044 4270.3952 30.512574
## X18 667.1700 1 2052529 2052528 74.49579 7355.8493 23.121475
## X19 607.8660 1 1687762 1687761 51.97649 3232.6405 28.340205
## X110 557.4576 1 1661854 1661853 50.51290 2989.9412 31.797018
## X111 505.5666 1 2483235 2483234 65.59972 5164.8193 44.601708
## X112 409.1976 1 1176756 1176755 55.41935 3686.1759 40.268090
## X113 327.6546 1 89997 89996 41.96932 2329.5421 3.391753
## X114 308.3808 1 89997 89996 26.32744 810.6761 8.226193
## X115 317.2764 1 89996 89995 34.41492 1421.8466 6.329055
## X116 357.3066 1 93594 93593 36.72605 1720.7885 3.849034
## X117 354.3414 1 89998 89997 41.34196 2303.1754 2.880369
## X118 434.4018 1 89996 89995 39.56860 1998.2432 2.794311
## X119 449.2278 1 89997 89996 36.80397 1719.3729 2.799078
## X120 447.7452 1 89996 89995 40.14235 2147.7991 2.444011
## X121 428.4714 1 89997 89996 38.71594 1929.3349 2.553959
## X122 403.2672 1 89997 89996 36.50339 1677.7801 2.815289
## X123 357.3066 1 89997 89996 36.00488 1565.5354 3.221453
## X124 327.6546 1 89996 89995 38.18180 1835.0715 3.447076
# Gráfico tiempo medio recorrido.
q <- ggplot(stats_by_month_by_membercasual,aes(x = group1,
y = round(mean/60, 2),
group = group2)) +
geom_line(aes(col = group2)) +
geom_point() +
theme(axis.text.x =element_text(angle=45),plot.title=element_text(size=14,hjust=0.5))+
labs(y="Tiempo Medio Recorrido (en minutos)",x="Mes",
title="Tiempo de recorrido en la bicicleta por meses del año",
color="Tipo de Usuario") +
scale_color_manual(values = c(casual = "#00AFBB", member = "#FC4E07"),
labels = c(casual = "Ocasional", member = "Suscriptor"))
q
Aqui vemos claramente como el tiempo medio recorrido en bicicleta por
los ciclistas ocasionales es mucho mayor que el tiempo medio recorrido
por los ciclistas que tienen una suscripcion anual, en todas las meses
del año.
Ahora haría falta saber si hay una relación significativa entre el tiempo de uso de la bicicleta y el ser ciclista ocasional o tener una suscripcion. O sea, tendremos que ver si el tiempo de uso de la bicicleta puede predecir si el ciclista es ocasional o suscriptor.
# Test estadístico ANOVA
result <- aov(diff_double ~ member_casual, data = df)
summary(result)
## Df Sum Sq Mean Sq F value Pr(>F)
## member_casual 1 1.342e+12 1.342e+12 12233 <2e-16 ***
## Residuals 5732911 6.291e+14 1.097e+08
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
El valor F, que es muy alto, nos viene a indicar que es probable que la variación de la variable tiempo recorrido en bicicleta causada por la variable tipo de usuario sea real y no debida al azar.
Lo cual queda confirmado por el valor de p, que es extremadamente pequeño (p=0.0000000000000002). Este valor describe la probabilidad de hallar un determinado conjunto de observaciones si la hipótesis nula fuera cierta, o sea, que no hubiera ninguna relación entre las variables. Cuanto mas pequeño es el valor p , mas probable es el rechazar la hipótesis nula y aceptar la alternativa, esto es, el de la existencia de relación entre las dos variables. Como el valor p es extremadamente pequeño, podemos concluir que el tiempo recorrido en bicicleta (la diferencia entre el momento en que se coge la bicicleta y el momento en que se deja) viene causada por el tipo de usuario. Sin embargo tenemos que tener en cuenta que la varianza residual es muy alta; esto es, hay mucha parte de la variación en el tiempo de uso de la bicicleta que no es explicada por la variable tipo de usuario.
Como hemos visto en los gráficos anteriores, los ciclistas ocasionales tienen un mayor tiempo de recorrido cuando cogen una bicileta que los ciclistas con suscripción. Y eso en todos los meses del año.
Por otra parte el test ANOVA nos indica que hay una relación significativa entre el tipo de usuario (ocasional o suscriptor) y el tiempo de recorrido con la bicicleta, o lo que es lo mismo, que podemos modelar o predecir el tiempo que se va a recorrer en bicicleta segun que el usuario sea ciclista ocasional o ciclista con suscripción.
Con ello podemos concluir que aunque es verdad que hay una diferencia entre los dos tipos de ciclistas, esta diferencia es en sentido contrario al que pensaba la directora de marketing, puesto que el negocio estaría en los ciclistas ocasionales que hacen un mayor recorrido cada vez que cogen la bicicleta.
Sin embargo este resultado habría que tomarlo con mucha precaución, como nos indica la elevada varianza residual en el test ANOVA.Lo cual indica que hay una parte elevada de la variación en la variable tiempo de uso o recorrido que está sin explicar.
En conclusion podriamos afirmar que con los datos presentes no podemos concretar cual debería ser la actuación, y deberíamos recabar mas datos. Tal vez realizando una encuesta donde recoger datos de edad, género, profesión, etc.