Escenario:

Cyclistic: Un programa de bicicletas compartidas que incluye 5,800 bicicletas y 600 estaciones. Cyclistic se destaca por ofrecer también bicicletas reclinadas, triciclos manuales y bicicletas de carga que ofrecen un uso más inclusivo de las bicicletas compartidas para las personas con discapacidad y los ciclistas que no pueden utilizar una bicicleta estándar de dos ruedas. La mayoría de los ciclistas eligen las bicicletas tradicionales, alrededor de un 8% de los ciclistas usan las opciones asistidas. Los usuarios de Cyclistic son más propensos a utilizar la bicicleta para recreación, pero alrededor del 30% la utiliza para ir al trabajo cada día.

Objetivo del Análisis: 

1- Importación y Preparación de Datos 

enero <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202401-divvy-tripdata.csv")

febrero <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202402-divvy-tripdata.csv")

marzo <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202403-divvy-tripdata.csv")

abril <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202404-divvy-tripdata.csv")

mayo <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202405-divvy-tripdata.csv")

junio <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202406-divvy-tripdata.csv")

julio <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202407-divvy-tripdata.csv")

agosto <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202408-divvy-tripdata.csv")

septiembre <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202409-divvy-tripdata.csv")

octubre <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202410-divvy-tripdata.csv")

noviembre <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202411-divvy-tripdata.csv")

diciembre <- read_csv("C:/Users/bruji/OneDrive/Desktop/Caso Data Analyst/202412-divvy-tripdata.csv")

> colnames(enero) .... (de Enero a Diciembre)

 [1] "ride_id"        "rideable_type"  "started_at"     "ended_at"       "start_station_name"

 [6] "start_station_id"   "end_station_name"   "end_station_id" "start_lat"      "start_lng"    

[11] "end_lat"            "end_lng"            "member_casual"


> colnames(diciembre)

 [1] "ride_id"        "rideable_type"  "started_at"     "ended_at"       "start_station_name"

 [6] "start_station_id"   "end_station_name"   "end_station_id" "start_lat"      "start_lng"    

[11] "end_lat"            "end_lng"            "member_casual"


Comprobamos nuevamente nuestro conjunto de datos en busca de posibles incongruencias:

str(enero)……… (análisis de todos los meses de Enero a Diciembre)

str(diciembre)

all_trips <- bind_rows(enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre)

all_trips$date <- as.Date(all_trips$started_at)     #Formato por defecto yyyy-mm-dd

all_trips$month <- format(as.Date(all_trips$date), "%m")    #Extraemos el mes de la fecha en formato numérico 

all_trips$day <- format(as.Date(all_trips$date), "%d")      #Extraemos el día del mes 

all_trips$year <- format(as.Date(all_trips$date), "%Y")    #Extraemos el año

all_trips$day_of_week <- format(as.Date(all_trips$date), "%A")  #Extraemos el nombre completo del día de la semana 

all_trips$ride_length <- difftime(all_trips$ended_at, all_trips$started_at)

is.factor(all_trips$ride_length)

all_trips$ride_length <- as.numeric(as.character(all_trips$ride_length))

is.numeric(all_trips$ride_length)

all_trips <- all_trips[all_trips$ride_length >= 0, ] 

Análisis

all_trips %>%

group_by(member_casual) %>%

summarise(number_of_rides = n(),

           'perc' = (n() / nrow(all_trips)) * 100)

 # A tibble: 2 × 3

  member_casual    number_of_rides  perc

  <chr>               <int> <dbl>

1 casual            2151563  36.7

2 member            3708778  63.3

# Agrupar y resumir los datos

summary_at <- all_trips %>%

group_by(member_casual) %>%

summarise(number_of_rides = n(),

           percent = (n() / nrow(all_trips)) * 100)

# Crear gráfico de barras

ggplot(summary_df, aes(x = member_casual, y = number_of_rides, fill = member_casual)) + geom_bar(stat = "identity") + labs(title = "Número de Viajes por Tipo de Usuario",x = "Tipo de Usuario",y = "Número de Viajes") + theme_minimal()

summary(all_trips$ride_length)

Min. 1st Qu.  Median Mean 3rd Qu. Max.

0.0   332.7   583.0  1039.1  1035.0             93596.0

 

all_trips <- all_trips %>% filter(ride_length < 24 * 60 * 60)  # Menos de 24 horas

También vemos que hay ay viajes con ride_length = 0, lo que podría indicar registros incorrectos, como, por ejemplo, errores en la recolección de datos o viajes cancelados.

Para corregir esto procederemos eliminar los registros con ride_length = 0 :

all_trips <- all_trips %>% filter(ride_length > 0)

all_trips %>%

  group_by(member_casual) %>%

  summarise(

mean_ride_length = mean(ride_length),

median_ride_length = median(ride_length),

max_ride_length = max(ride_length),

min_ride_length = min(ride_length)

  )

all_trips <- all_trips %>% filter(ride_length > 60)

A-  Basándonos en los datos obtenidos previamente podríamos recomendarle al negocio fomentar la conversión de usuarios a casuales a miembros. Dado que los usuarios casuales hacen viajes más largos se podrían ofrecer descuentos o promociones para que sea más atractivo suscribirse al servicio.

B-  Por otra parte, se podría optimizar la disponibilidad de bicicletas considerando que lo miembros realizan viajes más cortos y eficientes, lo que sugiere que se pueden redistribuir bicicletas en estaciones clave durante horas punta.

all_trips%>%

  group_by(month) %>%

  summarise(

count = n(),

'%' = (count / nrow(all_trips)) * 100,

members_p = mean(member_casual == "member") * 100,

casual_p = mean(member_casual == "casual") * 100,

`Member x Casual Perc Difer` = members_p - casual_p

  )


Diferencia entre miembros y usuarios casuales:

 

Los miembros dominan todo el año, pero su proporción disminuye en verano.

En invierno (enero - febrero), los miembros representan más del 79% de los viajes, mientras que los usuarios casuales son menos del 21%.

De esto podemos concluir que:

A.  Los usuarios casuales aumentan su demanda en verano lo que indicaría que hay más usuarios casuales que aprovechan el buen clima.

B. Los miembros son más estables, lo que sugiere que usan la bicicleta para transporte regular durante todo el año.

 

Recomendaciones para el negocio:


all_trips %>%

  group_by(month, member_casual) %>%

  summarise(count = n(), .groups = "drop") %>%

  ggplot(aes(x = month, y = count, color = member_casual, group = member_casual)) +

  geom_line(size = 1.2) + geom_point(size = 3) +                                                          labs(title = "Tendencia de Viajes por Mes y Tipo de Usuario", x = "Mes",                            y = "Número de Viajes", color = "Tipo de Usuario") + theme_minimal()


all_trips%>%

    group_by(member_casual, day_of_week) %>%

    summarise(mean_ride_length = mean(ride_length, na.rm = TRUE), .groups =  "drop")

all_trips %>%

  group_by(member_casual, day_of_week) %>%

  summarise(mean_ride_length = mean(ride_length, na.rm = TRUE), .groups = "drop") %>%

  ggplot(aes(x = day_of_week, y = mean_ride_length, fill = member_casual)) + geom_col(position = "dodge") +

  labs(title = "Duración Promedio de Viajes por Día de la Semana",

    x = "Día de la Semana", y = "Duración Promedio (segundos)", fill = "Tipo de Usuario") +

  theme_minimal()


all_trips %>%  

   mutate(weekday = wday(started_at, label = TRUE)) %>%   

   group_by(member_casual, weekday) %>%   

   summarise(number_of_rides = n(),                  

       average_duration = mean(ride_length)) %>%   

   arrange(member_casual, weekday)

all_trips %>%

  group_by(member_casual, day_of_week) %>%

  summarise(mean_ride_length = mean(ride_length, na.rm = TRUE), .groups = "drop") %>%

  ggplot(aes(x = day_of_week, y = mean_ride_length, fill = member_casual)) +

  geom_col(position = "dodge") +labs(title = "Duración Promedio de Viajes por Día de la Semana",x = "Día de la Semana", y = "Duración Promedio (segundos)", fill = "Tipo de Usuario") +theme_minimal()

all_trips %>% 

  mutate(weekday = wday(started_at, label = TRUE)) %>%  

  group_by(member_casual, weekday) %>%  

  summarise(number_of_rides = n(),             

         average_duration = mean(ride_length)) %>%  

all_trips %>%

  mutate(weekday = wday(started_at, label = TRUE)) %>%

  group_by(member_casual, weekday) %>%

  summarise(average_duration = mean(ride_length, na.rm = TRUE), .groups = "drop") %>%

  ggplot(aes(x = weekday, y = average_duration, color = member_casual, group = member_casual)) +geom_line(size = 1.2) +geom_point(size = 3) +

  labs(title = "Duración Promedio de Viajes por Día de la Semana", x = "Día de la Semana", y = "Duración Promedio (segundos)", color = "Tipo de Usuario") + theme_minimal()

Recomendaciones finales:



Finalmente, en base a los datos arrojados en el análisis realizado, se puede recomendar una campaña de Marketing basada en datos, como, por ejemplo: