Caso de estudio cyclistic

Cyclistic es una empresa de bicicletlas compartidas en chicago, la cual quiere maximizar la cantidad de membresías anuales, por lo tanto, debemos de encontrar las diferencias que existen entre los cyclistas anuales y los ocasionales para diseñar una estrategía de marketing.

Nuestra tarea es descubrir en qué se diferencian los cyclistas socios anuales y los ciclistas ocasionales con respecto al uso de las bicicletas de cyclistic.

¿En qué se diferencian los socios anuales y los ciclistas ocasionales con respecto al uso de las bicicletas de Cyclistic?

Tenemos un conjunto de datos de los últimos 12 meses de viajes de cyclistic, los vamos a limpiar y tranformar.

Cargamos las librerías necesarias.

Vamos a cargar los datos de los 12 meses y los unimos en un solo conjunto de datos:

enero <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\enero2022.csv")
febrero <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\febrero2022.csv")
marzo <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\marzo2022.csv")
abril <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\abril2022.csv")
mayo <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\mayo2022.csv")
junio <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\junio2022.csv")
julio <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\julio2022.csv")
agosto <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\agosto2022.csv")
sept2021 <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\septiembre2021.csv")
oct2021 <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\octubre2021.csv")
nov2021 <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\noviembre2021.csv")
dic2021 <- read.csv("D:\\Desktop\\CursoAD\\Caso_Practico_1_Archivos\\2021-2022\\diciembre2021.csv")
c_1 <- rbind(enero,febrero,marzo,abril,mayo,junio,julio,agosto,sept2021,oct2021,nov2021,dic2021)

Observamos el conjunto:

summary(c_1)
##    ride_id          rideable_type       started_at          ended_at        
##  Length:5883043     Length:5883043     Length:5883043     Length:5883043    
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  start_station_name start_station_id   end_station_name   end_station_id    
##  Length:5883043     Length:5883043     Length:5883043     Length:5883043    
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##    start_lat       start_lng         end_lat         end_lng      
##  Min.   :41.64   Min.   :-87.84   Min.   :41.39   Min.   :-88.97  
##  1st Qu.:41.88   1st Qu.:-87.66   1st Qu.:41.88   1st Qu.:-87.66  
##  Median :41.90   Median :-87.64   Median :41.90   Median :-87.64  
##  Mean   :41.90   Mean   :-87.65   Mean   :41.90   Mean   :-87.65  
##  3rd Qu.:41.93   3rd Qu.:-87.63   3rd Qu.:41.93   3rd Qu.:-87.63  
##  Max.   :45.64   Max.   :-73.80   Max.   :42.37   Max.   :-87.50  
##                                   NA's   :5727    NA's   :5727    
##  member_casual     
##  Length:5883043    
##  Class :character  
##  Mode  :character  
##                    
##                    
##                    
## 
colnames(c_1)
##  [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"
str(c_1)
## 'data.frame':    5883043 obs. of  13 variables:
##  $ ride_id           : chr  "C2F7DD78E82EC875" "A6CF8980A652D272" "BD0F91DFF741C66D" "CBB80ED419105406" ...
##  $ rideable_type     : chr  "electric_bike" "electric_bike" "classic_bike" "classic_bike" ...
##  $ started_at        : chr  "2022-01-13 11:59:47" "2022-01-10 08:41:56" "2022-01-25 04:53:40" "2022-01-04 00:18:04" ...
##  $ ended_at          : chr  "2022-01-13 12:02:44" "2022-01-10 08:46:17" "2022-01-25 04:58:01" "2022-01-04 00:33:00" ...
##  $ start_station_name: chr  "Glenwood Ave & Touhy Ave" "Glenwood Ave & Touhy Ave" "Sheffield Ave & Fullerton Ave" "Clark St & Bryn Mawr Ave" ...
##  $ start_station_id  : chr  "525" "525" "TA1306000016" "KA1504000151" ...
##  $ end_station_name  : chr  "Clark St & Touhy Ave" "Clark St & Touhy Ave" "Greenview Ave & Fullerton Ave" "Paulina St & Montrose Ave" ...
##  $ end_station_id    : chr  "RP-007" "RP-007" "TA1307000001" "TA1309000021" ...
##  $ start_lat         : num  42 42 41.9 42 41.9 ...
##  $ start_lng         : num  -87.7 -87.7 -87.7 -87.7 -87.6 ...
##  $ end_lat           : num  42 42 41.9 42 41.9 ...
##  $ end_lng           : num  -87.7 -87.7 -87.7 -87.7 -87.6 ...
##  $ member_casual     : chr  "casual" "casual" "member" "casual" ...
vista <- head(c_1)
vista
##            ride_id rideable_type          started_at            ended_at
## 1 C2F7DD78E82EC875 electric_bike 2022-01-13 11:59:47 2022-01-13 12:02:44
## 2 A6CF8980A652D272 electric_bike 2022-01-10 08:41:56 2022-01-10 08:46:17
## 3 BD0F91DFF741C66D  classic_bike 2022-01-25 04:53:40 2022-01-25 04:58:01
## 4 CBB80ED419105406  classic_bike 2022-01-04 00:18:04 2022-01-04 00:33:00
## 5 DDC963BFDDA51EEA  classic_bike 2022-01-20 01:31:10 2022-01-20 01:37:12
## 6 A39C6F6CC0586C0B  classic_bike 2022-01-11 18:48:09 2022-01-11 18:51:31
##              start_station_name start_station_id              end_station_name
## 1      Glenwood Ave & Touhy Ave              525          Clark St & Touhy Ave
## 2      Glenwood Ave & Touhy Ave              525          Clark St & Touhy Ave
## 3 Sheffield Ave & Fullerton Ave     TA1306000016 Greenview Ave & Fullerton Ave
## 4      Clark St & Bryn Mawr Ave     KA1504000151     Paulina St & Montrose Ave
## 5   Michigan Ave & Jackson Blvd     TA1309000002        State St & Randolph St
## 6         Wood St & Chicago Ave              637       Honore St & Division St
##   end_station_id start_lat start_lng  end_lat   end_lng member_casual
## 1         RP-007  42.01280 -87.66591 42.01256 -87.67437        casual
## 2         RP-007  42.01276 -87.66597 42.01256 -87.67437        casual
## 3   TA1307000001  41.92560 -87.65371 41.92533 -87.66580        member
## 4   TA1309000021  41.98359 -87.66915 41.96151 -87.67139        casual
## 5   TA1305000029  41.87785 -87.62408 41.88462 -87.62783        member
## 6   TA1305000034  41.89563 -87.67207 41.90312 -87.67394        member

Buscamos y exploramos valores nulos:

any(is.na(c_1))
## [1] TRUE
apply(is.na(c_1), 2, sum)
##            ride_id      rideable_type         started_at           ended_at 
##                  0                  0                  0                  0 
## start_station_name   start_station_id   end_station_name     end_station_id 
##                  0                  0                  0                  0 
##          start_lat          start_lng            end_lat            end_lng 
##                  0                  0               5727               5727 
##      member_casual 
##                  0

Observamos que las columnas end_lat y end_Ing son las que contienen los valores nulos, al ser un conjunto de datos ficticio, queda a mi criterio eliminarlos o no.

Eliminamos los valores nulos:

c_2 <- na.omit(c_1)#Eliminé 5,727
sum(is.na(c_2))
## [1] 0

Observamos que el valor de valores na es 0.

Borramos las columnas que considero no necesito para el análisis por ahora:

c_3 <- c_2 %>%  
  select(-c(start_lat, start_lng, end_lat, end_lng))

Cambiamos las columnas started_at y ended_at a formato ymd_hms:

col_started <- ymd_hms(c_3$started_at)
col_ended <- ymd_hms(c_3$ended_at)
#quitamos las columnas con el formato chr
c_4 <- select(c_3, -ended_at, -started_at)
#agregamos las columnas con el formato ymd:hms al conjunto de datos
c_5 <- c_4 %>% mutate(started_at = col_started)%>%
  mutate(ended_at = col_ended)
c_5[1:5,8:9]
##            started_at            ended_at
## 1 2022-01-13 11:59:47 2022-01-13 12:02:44
## 2 2022-01-10 08:41:56 2022-01-10 08:46:17
## 3 2022-01-25 04:53:40 2022-01-25 04:58:01
## 4 2022-01-04 00:18:04 2022-01-04 00:33:00
## 5 2022-01-20 01:31:10 2022-01-20 01:37:12

Creamos la columna “duración viaje” restando a started_at, ended_at. Se crea en segundos pero para fines visuales, también creamos una en formato hms:

c_6 <- c_5 %>% mutate(duracion_viaje_secs = ended_at - started_at)
c_7 <- c_6 %>% mutate(duracion_viaje = as.hms(ended_at - started_at))
c_7[1:5,9:11]
##              ended_at duracion_viaje_secs duracion_viaje
## 1 2022-01-13 12:02:44            177 secs       00:02:57
## 2 2022-01-10 08:46:17            261 secs       00:04:21
## 3 2022-01-25 04:58:01            261 secs       00:04:21
## 4 2022-01-04 00:33:00            896 secs       00:14:56
## 5 2022-01-20 01:37:12            362 secs       00:06:02

Creamos una columna con los días de la semana de los viajes, empezando 1 en domingo y 7 sábado. De igual manera creamos una en formato chr:

c_8 <- c_7 %>% mutate(dia_semana = (as.POSIXlt(c_5$started_at)$wday+1)) %>%
  mutate(dia = (weekdays(c_5$started_at)))
c_8[1:5,10:13]
##   duracion_viaje_secs duracion_viaje dia_semana    dia
## 1            177 secs       00:02:57          5 jueves
## 2            261 secs       00:04:21          2  lunes
## 3            261 secs       00:04:21          3 martes
## 4            896 secs       00:14:56          3 martes
## 5            362 secs       00:06:02          5 jueves

Creamos una columna para extraer los meses de los viajes:

c_9 <- c_8%>%
  mutate(mes_letra = format(c_6$started_at, "%B"))
c_9[1:5,11:14]
##   duracion_viaje dia_semana    dia mes_letra
## 1       00:02:57          5 jueves     enero
## 2       00:04:21          2  lunes     enero
## 3       00:04:21          3 martes     enero
## 4       00:14:56          3 martes     enero
## 5       00:06:02          5 jueves     enero

Creamos una columna para la temporada de los viajes de acuerdo al mes:

c_10 <- c_9 %>% 
  mutate(temporada = case_when(
    (mes_letra == "diciembre") | (mes_letra == "enero")~ "invierno",
    (mes_letra == "marzo") | (mes_letra == "abril") ~ "primavera",
    (mes_letra == "junio") | (mes_letra == "julio") ~ "verano",
    (mes_letra == "febrero") ~ "invierno",
    (mes_letra == "mayo") ~ "primavera",
    (mes_letra == "agosto") ~ "verano",
    (mes_letra == "noviembre") ~ "otoño",
    (mes_letra == "septiembre") | (mes_letra == "octubre") ~ "otoño"))
c_10[1:5,13:15]
##      dia mes_letra temporada
## 1 jueves     enero  invierno
## 2  lunes     enero  invierno
## 3 martes     enero  invierno
## 4 martes     enero  invierno
## 5 jueves     enero  invierno

Revisamos que todos los meses sean proporcionales a la cantidad de variables;

length(c_10$temporada [c_10$temporada == "primavera"])
## [1] 1288844
length(c_10$temporada [c_10$temporada == "verano"])
## [1] 2375779
length(c_10$temporada [c_10$temporada == "otoño"])
## [1] 1746081
length(c_10$temporada [c_10$temporada == "invierno"])
## [1] 466612

Análisis de los datos

Comparamos a los miembros anuales con los ciclistas ocasionales:

aggregate(c_10$duracion_viaje ~ c_10$member_casual, FUN = mean)
##   c_10$member_casual c_10$duracion_viaje
## 1             casual      1425.9661 secs
## 2             member       755.3348 secs
aggregate(c_10$duracion_viaje ~ c_10$member_casual, FUN = median)
##   c_10$member_casual c_10$duracion_viaje
## 1             casual            00:13:53
## 2             member            00:08:58
aggregate(c_10$duracion_viaje ~ c_10$member_casual, FUN = max)
##   c_10$member_casual c_10$duracion_viaje
## 1             casual        2442301 secs
## 2             member          89996 secs
aggregate(c_10$duracion_viaje ~ c_10$member_casual, FUN = min)
##   c_10$member_casual c_10$duracion_viaje
## 1             casual          -8245 secs
## 2             member          -7745 secs

Nos damos cuenta que hay viajes en negativo, decidimos eliminarlos

Eliminar viajes con valores negativos:

cyclistic <- c_10[!(c_10$start_station_name == "HQ QR" | c_10$duracion_viaje_secs<0),]

Media duración de los viajes:

as.hms(mean(cyclistic$duracion_viaje_secs))
## 00:17:16.489844
mean(cyclistic$duracion_viaje)
## Time difference of 1036.49 secs

Observamos las modas:

mfv(cyclistic$dia)
## [1] "sábado"
mfv(cyclistic$mes_letra)
## [1] "julio"
mfv(cyclistic$temporada)
## [1] "verano"

Cálculamos el promedio de duración de viaje por tipo de ciclistas:

aggregate(cyclistic$duracion_viaje_secs~member_casual,cyclistic, mean,na.rm=TRUE)
##   member_casual cyclistic$duracion_viaje_secs
## 1        casual                1426.0544 secs
## 2        member                 755.3726 secs

Nos damos cuenta que hay ciclistas con viajes de 0 segundos, los cuales también eliminamos:

cyclisticV2 <- cyclistic[!(cyclistic$duracion_viaje_secs<=0),]

Tiempo de viaje promedio por día por cada tipo de ciclista:

aggregate(cyclisticV2$duracion_viaje ~ cyclisticV2$member_casual + cyclisticV2$dia, FUN = mean)
##    cyclisticV2$member_casual cyclisticV2$dia cyclisticV2$duracion_viaje
## 1                     casual         domingo             1655.0035 secs
## 2                     member         domingo              842.7542 secs
## 3                     casual          jueves             1266.2252 secs
## 4                     member          jueves              726.2407 secs
## 5                     casual           lunes             1470.4409 secs
## 6                     member           lunes              733.0142 secs
## 7                     casual          martes             1247.5052 secs
## 8                     member          martes              715.3362 secs
## 9                     casual       miércoles             1226.3644 secs
## 10                    member       miércoles              719.5006 secs
## 11                    casual          sábado             1580.2663 secs
## 12                    member          sábado              841.0429 secs
## 13                    casual         viernes             1329.5970 secs
## 14                    member         viernes              740.4586 secs

Visualización de la información con Power BI

¿Qué es Power BI?

Número de viajes por día y promedio de duración:

Gráfica 1: número de viajes por día y promedio de duración La imagen nos muestra que los ciclistas ocasionales prefieren los fines de semana para realiza sus viajes. Los ciclistas miembros prefieren los viajes entre semana y en promedio son viajes cortos a comparación de los ciclistas ocasionales que suelen realizar viajes más largos.

Promedio de duración de viaje por días de la semana

Gráfica 2: Promedio de duracion de viaje por días de la semana Los usuarios casuales en promedio realizan viajes más largos que los miembros anuales. El pico de viajes se encuentra entre sábado y domingo, siendo estos viajes realizados en su mayoría por usuarios ocasionales.

Número de viajes por meses y promedio de duración del viaje

Gráfica 3: Número de viajes por meses y promedio de duración de viaje Los viajes de ciclistas ocasionales aumentan en junio y julio, mientras tanto julio y agosto son los meses preferidos por los ciclistas miembros.

Tipo de bicicleta preferida por los ciclistas:

Gráfica 4: bicicleta preferida La bicicleta eléctrica es la preferica por los ciclistas casuales, mientras que la bicicleta clásica es elegida más por los miembros ciclistas.

Temporada favorita por los ciclistas:

Gráfica 5: Temporada

Los dos tipos de ciclistas prefieren los veranos para realizar sus viajes y reducen su cantidad de viajes considerablemente en invierno

Recomendaciones finales

Tres recomendaciones que pude observar a partir del comportamiento de los datos:

Información complementaria de los datos

Conjuntos de datos abiertos, bajo la licencia Motivate, almacenados en: https://divvy-tripdata.s3.amazonaws.com/index.html

Información de contacto

Mariana Raquel Flores Carrillo ir a linkedin: https://www.linkedin.com/in/mariana-raquel-flores-carrillo-20201b247/