Cyclistic, bicicletas compartidas de Chicago es un caso práctico ficticio del curso de Análisis de datos de Google 2023 de Coursera.
Para responder a las preguntas clave de la empresa en este caso práctico, se seguiran los pasos del proceso de análisis de datos vistos durante el curso: preguntar, preparar, procesar, analizar, compartir y actuar.
Eres el analista de datos júnior que trabaja en el equipo de analistas de marketing de Cyclistic. La directora de marketing cree que el éxito futuro de la empresa depende de maximizar la cantidad de membresías anuales. Por lo tanto, tu equipo quiere entender qué diferencias existen en el uso de las bicicletas Cyclistic entre los ciclistas ocasionales y los miembros anuales.
A través de estos conocimientos, Su equipo diseñará una nueva estrategia de marketing para convertir a los ciclistas ocasionales en miembros anuales. Sin embargo, antes de eso, los ejecutivos de Cyclistic deben aprobar tus recomendaciones; por eso, debes respaldar tu propuesta con una visión convincente de los datos y visualizaciones profesionales de los mismos.
Lily Moreno. La directora de marketing es responsable del desarrollo de campañas e iniciativas para promover el programa de bicicletas compartidas. Sus campañas pueden incluir correo electrónico, redes sociales y otros canales. Cree que en lugar de crear una campaña de marketing que apunte a todos los clientes nuevos, sería mejor apuntarla hacia los ciclistas ocasionales para convertirlos en miembros anuales. Cree que maximizar el número de miembros anuales será clave para el crecimiento futuro. Ella señala que los ciclistas ocasionales ya conocen el programa de Cyclistic y han elegido a Cyclistic para sus necesidades de movilidad. Equipo de análisis computacional de datos de marketing de Cyclistic: Un equipo de analistas de datos que se encargan de recopilar, analizar e informar datos que ayudan a conducir la estrategia de marketing de Cyclistic. Equipo ejecutivo de Cyclistic: El equipo es sumamente detallista, decidirá si aprueba el programa de marketing recomendado. Los analistas financieros de Cyclistic que llegaron a la conclusión de que los miembros anuales son mucho más rentables que los ciclistas ocasionales. Cyclistic. Las bicicletas se pueden desbloquear desde una estación y devolverse en cualquier otra estación del sistema en cualquier momento. Planes de precios:
o A los clientes que compran pases de un solo viaje o pases de un día completo se los llama ocasionales.
o A los clientes que compran membresías anuales se llaman miembros.
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 como son: reclinadas, triciclos manuales, bicicletas de carga.
o La mayoría de los ciclistas eligen las bicicletas tradicionales. Alrededor de un 8% de los ciclistas usan las opciones asistidas.
o Los usuarios de Cyclistic son más propensos a utilizar la bicicleta para recreación. o Alrededor del 30% la utiliza para ir al trabajo cada día.
En 2016, Cyclistic lanzó una exitosa oferta de bicicletas compartidas. Desde entonces, el programa creció hasta alcanzar una flota de 5,824 bicicletas georreferenciadas y bloqueadas en una red de 692 estaciones en toda Chicago. Hasta ahora, la estrategia de marketing de Cyclistic se basaba en la construcción de un reconocimiento de marca general y en atraer a amplios segmentos de consumidores. Uno de los enfoques que ayudó a hacer esto posible fue la flexibilidad de sus planes de precios.
Teniendo el conocimiento del contexto de la empresa y de la meta de Lily Moreno que es diseñar estrategias de marketing orientadas a convertir a los ciclistas ocasionales en miembros anuales a traves de analizar los datos históricos de viajes en bicicleta de Cyclistic para identificar tendencias, ella te asigna una tema a resolver:
o Tarea empresarial. Buscar en qué se diferencian los socios anuales y los ciclistas ocasionales con respecto al uso de las bicicletas de Cyclistic.
Detalles a considerar sobre los datos:
o Fuente de datos utilizadas. Solo una, que es interna osea la misma empresa. o Ubicación y accesibilidad.
Todos los datos han sido proporcionados por Motivate International Inc. para explorar cómo difieren los tipos de clientes que usan las bicicletas Cyclistic. Se ubican en un servidor del cual se pueden descargar.
o Autorización. Se tiene autorización bajo esta licencia: https://www.divvybikes.com/data-license-agreement.
o Privacidad. Se prohíbe usar información de identificación personal de los ciclistas. Esto significa que no podrás conectar las compras de pases con los números de tarjetas de crédito para determinar si los ciclistas ocasionales viven en el área de servicio de Cyclistic o si compraron varios pases de un solo viaje.
o ¿Son confiables?. Si.
o ¿Son originales? Si pues fueon creados por la propia empresa y no por fuentes externas.
o ¿Son integrales? Si pues cuentan con información que puede responder la pregunta empresarial.
o ¿Esta actualizada? Si pues aparecen actualizaciones mensuales.
o ¿Estan citados? Si
Organización de los datos. Los archivos descargados estaban comprimidos en formato zip y organizados por nombre de año y mes donde se ve que siguen una nomenclatura para sus nombre de archivo.
Integridad de los datos. Primero preparo el ambiente de trabajo. El software de trabajo que elegí para el análisis de los datos fue Rstudio porque soporta una gran cantidad de información.
Configurar mi entorno de RStudio instalando y cargando las librerias de los paquetes necesarios y los archivos de los últimos 12 meses de Cyclistic, que van de Agosto de 2022 a Julio de 2023.
Instalación de paquetes y carga de librerias.
Con la función read_cvs() cargamos los archivos y les asignamos un nombre diferente para que sea mas fácil trabajar con ellos.
Todos los archivos estan en formato CSV separados por comas. Al cargar los archivos se ve una inconsistencia en el nombre del archivo:
202209-divvy-publictripdata.csv que se nombro como marco de datos agosto_2022 ya que no sigue el mismo formato en el nombre ni en el tipo de datos de las columnas: started_at y ended_at como los demás archivos.
Al ejecutar la función glimpse() se muestra la siguiente información de los marcos de datos en cada uno de los 12 meses.
glimpse(agosto_2022)
Rows: 785,932
Columns: 13
$ ride_id <chr> "550CF7EFEAE0C618", "DAD198F405F9C5F…
$ rideable_type <chr> "electric_bike", "electric_bike", "e…
$ started_at <chr> "07/08/2022 21:34", "08/08/2022 14:3…
$ ended_at <chr> "07/08/2022 21:41", "08/08/2022 14:5…
$ start_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ start_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ end_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ end_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ start_lat <dbl> 41.93, 41.89, 41.97, 41.94, 41.85, 4…
$ start_lng <dbl> -87.69, -87.64, -87.69, -87.65, -87.…
$ end_lat <dbl> 41.94, 41.92, 41.97, 41.97, 41.84, 4…
$ end_lng <dbl> -87.72, -87.64, -87.66, -87.69, -87.…
$ member_casual <chr> "casual", "casual", "casual", "casua…
glimpse(septiembre_2022)
Rows: 701,339
Columns: 13
$ ride_id <chr> "5156990AC19CA285", "E12D4A16BF51C27…
$ rideable_type <chr> "electric_bike", "electric_bike", "e…
$ started_at <dttm> 2022-09-01 08:36:22, 2022-09-01 17:…
$ ended_at <dttm> 2022-09-01 08:39:05, 2022-09-01 17:…
$ start_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ start_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ end_station_name <chr> "California Ave & Milwaukee Ave", NA…
$ end_station_id <chr> "13084", NA, NA, NA, NA, NA, NA, NA,…
$ start_lat <dbl> 41.93, 41.87, 41.87, 41.93, 41.92, 4…
$ start_lng <dbl> -87.69, -87.62, -87.62, -87.69, -87.…
$ end_lat <dbl> 41.92269, 41.87000, 41.87000, 41.940…
$ end_lng <dbl> -87.69715, -87.62000, -87.62000, -87…
$ member_casual <chr> "casual", "casual", "casual", "casua…
glimpse(octubre_2022)
Rows: 558,685
Columns: 13
$ ride_id <chr> "A50255C1E17942AB", "DB692A70BD2DD4E3", "3C02727A…
$ rideable_type <chr> "classic_bike", "electric_bike", "electric_bike",…
$ started_at <dttm> 2022-10-14 17:13:30, 2022-10-01 16:29:26, 2022-1…
$ ended_at <dttm> 2022-10-14 17:19:39, 2022-10-01 16:49:06, 2022-1…
$ start_station_name <chr> "Noble St & Milwaukee Ave", "Damen Ave & Charlest…
$ start_station_id <chr> "13290", "13288", "655", "KA1504000133", "13028",…
$ end_station_name <chr> "Larrabee St & Division St", "Damen Ave & Cullert…
$ end_station_id <chr> "KA1504000079", "13089", "TA1307000140", "620", "…
$ start_lat <dbl> 41.90068, 41.92004, 41.97988, 41.90227, 41.87475,…
$ start_lng <dbl> -87.66260, -87.67794, -87.68190, -87.62769, -87.6…
$ end_lat <dbl> 41.90349, 41.85497, 41.96640, 41.89820, 41.86610,…
$ end_lng <dbl> -87.64335, -87.67570, -87.68870, -87.63754, -87.6…
$ member_casual <chr> "member", "casual", "member", "member", "casual",…
glimpse(noviembre_2022)
Rows: 337,735
Columns: 13
$ ride_id <chr> "BCC66FC6FAB27CC7", "772AB67E902C180F", "585EAD07…
$ rideable_type <chr> "electric_bike", "classic_bike", "classic_bike", …
$ started_at <dttm> 2022-11-10 06:21:55, 2022-11-04 07:31:55, 2022-1…
$ ended_at <dttm> 2022-11-10 06:31:27, 2022-11-04 07:46:25, 2022-1…
$ start_station_name <chr> "Canal St & Adams St", "Canal St & Adams St", "In…
$ start_station_id <chr> "13011", "13011", "SL-005", "SL-005", "SL-005", "…
$ end_station_name <chr> "St. Clair St & Erie St", "St. Clair St & Erie St…
$ end_station_id <chr> "13016", "13016", "13016", "13016", "13016", "TA1…
$ start_lat <dbl> 41.87940, 41.87926, 41.86789, 41.86789, 41.86789,…
$ start_lng <dbl> -87.63985, -87.63990, -87.62304, -87.62304, -87.6…
$ end_lat <dbl> 41.89435, 41.89435, 41.89435, 41.89435, 41.89435,…
$ end_lng <dbl> -87.62280, -87.62280, -87.62280, -87.62280, -87.6…
$ member_casual <chr> "member", "member", "member", "member", "member",…
glimpse(diciembre_2022)
Rows: 181,806
Columns: 13
$ ride_id <chr> "65DBD2F447EC51C2", "0C201AA7EA0EA1AD", "E0B148CC…
$ rideable_type <chr> "electric_bike", "classic_bike", "electric_bike",…
$ started_at <dttm> 2022-12-05 10:47:18, 2022-12-18 06:42:33, 2022-1…
$ ended_at <dttm> 2022-12-05 10:56:34, 2022-12-18 07:08:44, 2022-1…
$ start_station_name <chr> "Clifton Ave & Armitage Ave", "Broadway & Belmont…
$ start_station_id <chr> "TA1307000163", "13277", "TA1306000015", "KA15030…
$ end_station_name <chr> "Sedgwick St & Webster Ave", "Sedgwick St & Webst…
$ end_station_id <chr> "13191", "13191", "13016", "13134", "13288", "KA1…
$ start_lat <dbl> 41.91824, 41.94011, 41.88592, 41.83846, 41.89595,…
$ start_lng <dbl> -87.65711, -87.64545, -87.65113, -87.63541, -87.6…
$ end_lat <dbl> 41.92217, 41.92217, 41.89435, 41.88137, 41.92008,…
$ end_lng <dbl> -87.63889, -87.63889, -87.62280, -87.67493, -87.6…
$ member_casual <chr> "member", "casual", "member", "member", "casual",…
glimpse(enero_2023)
Rows: 190,301
Columns: 13
$ ride_id <chr> "F96D5A74A3E41399", "13CB7EB698CEDB88", "BD88A2E6…
$ rideable_type <chr> "electric_bike", "classic_bike", "electric_bike",…
$ started_at <dttm> 2023-01-21 20:05:42, 2023-01-10 15:37:36, 2023-0…
$ ended_at <dttm> 2023-01-21 20:16:33, 2023-01-10 15:46:05, 2023-0…
$ start_station_name <chr> "Lincoln Ave & Fullerton Ave", "Kimbark Ave & 53r…
$ start_station_id <chr> "TA1309000058", "TA1309000037", "RP-005", "TA1309…
$ end_station_name <chr> "Hampden Ct & Diversey Ave", "Greenwood Ave & 47t…
$ end_station_id <chr> "202480.0", "TA1308000002", "599", "TA1308000002"…
$ start_lat <dbl> 41.92407, 41.79957, 42.00857, 41.79957, 41.79957,…
$ start_lng <dbl> -87.64628, -87.59475, -87.69048, -87.59475, -87.5…
$ end_lat <dbl> 41.93000, 41.80983, 42.03974, 41.80983, 41.80983,…
$ end_lng <dbl> -87.64000, -87.59938, -87.69941, -87.59938, -87.5…
$ member_casual <chr> "member", "member", "casual", "member", "member",…
glimpse(febrero_2023)
Rows: 190,445
Columns: 13
$ ride_id <chr> "CBCD0D7777F0E45F", "F3EC5FCE5FF39DE9", "E54C1F27…
$ rideable_type <chr> "classic_bike", "electric_bike", "classic_bike", …
$ started_at <dttm> 2023-02-14 11:59:42, 2023-02-15 13:53:48, 2023-0…
$ ended_at <dttm> 2023-02-14 12:13:38, 2023-02-15 13:59:08, 2023-0…
$ start_station_name <chr> "Southport Ave & Clybourn Ave", "Clarendon Ave & …
$ start_station_id <chr> "TA1309000030", "13379", "TA1309000030", "TA13090…
$ end_station_name <chr> "Clark St & Schiller St", "Sheridan Rd & Lawrence…
$ end_station_id <chr> "TA1309000024", "TA1309000041", "13156", "TA13090…
$ start_lat <dbl> 41.92077, 41.95788, 41.92077, 41.92087, 41.79483,…
$ start_lng <dbl> -87.66371, -87.64958, -87.66371, -87.66373, -87.6…
$ end_lat <dbl> 41.90799, 41.96952, 41.88042, 41.87943, 41.78053,…
$ end_lng <dbl> -87.63150, -87.65469, -87.65552, -87.63550, -87.6…
$ member_casual <chr> "casual", "casual", "member", "member", "member",…
glimpse(marzo_2023)
Rows: 258,678
Columns: 13
$ ride_id <chr> "6842AA605EE9FBB3", "F984267A75B99A8C", "FF7CF57C…
$ rideable_type <chr> "electric_bike", "electric_bike", "classic_bike",…
$ started_at <dttm> 2023-03-16 08:20:34, 2023-03-04 14:07:06, 2023-0…
$ ended_at <dttm> 2023-03-16 08:22:52, 2023-03-04 14:15:31, 2023-0…
$ start_station_name <chr> "Clark St & Armitage Ave", "Public Rack - Kedzie …
$ start_station_id <chr> "13146", "491", "620", "TA1306000003", "18067", "…
$ end_station_name <chr> "Larrabee St & Webster Ave", NA, "Clark St & Rand…
$ end_station_id <chr> "13193", NA, "TA1305000030", "13154", "TA13060000…
$ start_lat <dbl> 41.91841, 41.97000, 41.89820, 41.88872, 41.91448,…
$ start_lng <dbl> -87.63645, -87.71000, -87.63754, -87.64445, -87.6…
$ end_lat <dbl> 41.92182, 41.95000, 41.88458, 41.91052, 41.88578,…
$ end_lng <dbl> -87.64414, -87.71000, -87.63189, -87.65311, -87.6…
$ member_casual <chr> "member", "member", "member", "member", "member",…
glimpse(abril_2023)
Rows: 426,590
Columns: 13
$ ride_id <chr> "8FE8F7D9C10E88C7", "34E4ED3ADF1D821B", "5296BF07…
$ rideable_type <chr> "electric_bike", "electric_bike", "electric_bike"…
$ started_at <dttm> 2023-04-02 08:37:28, 2023-04-19 11:29:02, 2023-0…
$ ended_at <dttm> 2023-04-02 08:41:37, 2023-04-19 11:52:12, 2023-0…
$ start_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ start_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ end_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ end_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ start_lat <dbl> 41.80, 41.87, 41.93, 41.92, 41.91, 41.91, 41.93, …
$ start_lng <dbl> -87.60, -87.65, -87.66, -87.65, -87.65, -87.63, -…
$ end_lat <dbl> 41.79, 41.93, 41.93, 41.91, 41.91, 41.92, 41.91, …
$ end_lng <dbl> -87.60, -87.68, -87.66, -87.65, -87.63, -87.65, -…
$ member_casual <chr> "member", "member", "member", "member", "member",…
glimpse(mayo_2023)
Rows: 604,827
Columns: 13
$ ride_id <chr> "0D9FA920C3062031", "92485E5FB5888ACD", "FB144B3F…
$ rideable_type <chr> "electric_bike", "electric_bike", "electric_bike"…
$ started_at <dttm> 2023-05-07 19:53:48, 2023-05-06 18:54:08, 2023-0…
$ ended_at <dttm> 2023-05-07 19:58:32, 2023-05-06 19:03:35, 2023-0…
$ start_station_name <chr> "Southport Ave & Belmont Ave", "Southport Ave & B…
$ start_station_id <chr> "13229", "13229", "13162", "13196", "TA1308000047…
$ end_station_name <chr> NA, NA, NA, "Damen Ave & Cortland St", "Southport…
$ end_station_id <chr> NA, NA, NA, "13133", "13229", "TA1306000029", "13…
$ start_lat <dbl> 41.93941, 41.93948, 41.85379, 41.89456, 41.95708,…
$ start_lng <dbl> -87.66383, -87.66385, -87.64672, -87.65345, -87.6…
$ end_lat <dbl> 41.93000, 41.94000, 41.86000, 41.91598, 41.93948,…
$ end_lng <dbl> -87.65000, -87.69000, -87.65000, -87.67733, -87.6…
$ member_casual <chr> "member", "member", "member", "member", "member",…
glimpse(junio_2023)
Rows: 719,618
Columns: 13
$ ride_id <chr> "6F1682AC40EB6F71", "622A1686D64948EB", "3C88859D…
$ rideable_type <chr> "electric_bike", "electric_bike", "electric_bike"…
$ started_at <dttm> 2023-06-05 13:34:12, 2023-06-05 01:30:22, 2023-0…
$ ended_at <dttm> 2023-06-05 14:31:56, 2023-06-05 01:33:06, 2023-0…
$ start_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ start_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ end_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ end_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ start_lat <dbl> 41.91, 41.94, 41.95, 41.99, 41.98, 41.99, 41.88, …
$ start_lng <dbl> -87.69, -87.65, -87.68, -87.65, -87.66, -87.68, -…
$ end_lat <dbl> 41.91, 41.94, 41.92, 41.98, 41.99, 41.94, 41.88, …
$ end_lng <dbl> -87.70, -87.65, -87.63, -87.66, -87.65, -87.65, -…
$ member_casual <chr> "member", "member", "member", "member", "member",…
glimpse(julio_2023)
Rows: 767,650
Columns: 13
$ ride_id <chr> "9340B064F0AEE130", "D1460EE3CE0D8AF8", "DF41BE31B895A25…
$ rideable_type <chr> "electric_bike", "classic_bike", "classic_bike", "electr…
$ started_at <dttm> 2023-07-23 20:06:14, 2023-07-23 17:05:07, 2023-07-23 10…
$ ended_at <dttm> 2023-07-23 20:22:44, 2023-07-23 17:18:37, 2023-07-23 10…
$ start_station_name <chr> "Kedzie Ave & 110th St", "Western Ave & Walton St", "Wes…
$ start_station_id <chr> "20204", "KA1504000103", "KA1504000103", "13155", "TA130…
$ end_station_name <chr> "Public Rack - Racine Ave & 109th Pl", "Milwaukee Ave & …
$ end_station_id <chr> "877", "13033", "TA1305000041", "TA1305000032", "TA13080…
$ start_lat <dbl> 41.69241, 41.89842, 41.89842, 41.88411, 41.96709, 41.884…
$ start_lng <dbl> -87.70091, -87.68660, -87.68660, -87.65694, -87.66729, -…
$ end_lat <dbl> 41.69483, 41.89158, 41.90940, 41.88275, 41.96398, 41.885…
$ end_lng <dbl> -87.65304, -87.64838, -87.67769, -87.64119, -87.63818, -…
$ member_casual <chr> "member", "member", "member", "member", "member", "membe…
Se puede ver que el marco de datos agosto_2022 tiene el tipo de dato chr en vez de dttm en las columnas: started_at y ended_at. Se cambiaran a dttm con la siguiente instrucción y se comprobara el cambio.
agosto_2022 <- mutate(agosto_2022, started_at=as.POSIXct(started_at, format= "%d/%m/%Y %H:%M"))
glimpse(agosto_2022)
Rows: 785,932
Columns: 13
$ ride_id <chr> "550CF7EFEAE0C618", "DAD198F405F9C5F5", "E6F2BC47…
$ rideable_type <chr> "electric_bike", "electric_bike", "electric_bike"…
$ started_at <dttm> 2022-08-07 21:34:00, 2022-08-08 14:39:00, 2022-0…
$ ended_at <dttm> 2022-08-07 21:41:00, 2022-08-08 14:53:00, 2022-0…
$ start_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ start_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ end_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ end_station_id <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ start_lat <dbl> 41.93, 41.89, 41.97, 41.94, 41.85, 41.79, 41.89, …
$ start_lng <dbl> -87.69, -87.64, -87.69, -87.65, -87.65, -87.72, -…
$ end_lat <dbl> 41.94, 41.92, 41.97, 41.97, 41.84, 41.82, 41.89, …
$ end_lng <dbl> -87.72, -87.64, -87.66, -87.69, -87.66, -87.69, -…
$ member_casual <chr> "casual", "casual", "casual", "casual", "casual",…
Se puede comprobar con la información mostrada que todos los marcos de datos cuenta con las mismas 13 columnas y con el mismo tipo de datos por lo cual es posible unirlos para empezar a realizar el procesamiento de los datos.
Se utiliza la siguiente instrucción para unir los marcos de datos. año_viajes <- bind_rows(agosto_2022,septiembre_2022,octubre_2022,noviembre_2022,diciembre_2022,enero_2023,febrero_2023,marzo_2023,abril_2023,mayo_2023,junio_2023,julio_2023)
Se eliminan las columnas: start_lat, end_lat, start_lng, end_lng, start_station_id, end_station_id ya que pueden interferir con la política de privacidad y no resultan útiles para el análisis según mi criterio.
año_viajes <- año_viajes %>% select(-c(start_lat, start_lng, end_lat, end_lng, start_station_id, end_station_id))
colnames(año_viajes)
[1] "ride_id" "rideable_type" "started_at"
[4] "ended_at" "start_station_name" "end_station_name"
[7] "member_casual"
Una vez revisado el tema de la integridad de los datos se pasa al procesamiento, para limpiar los datos verificando si hay errores en ellos para su posterior análisis.
skim(año_viajes)
── Data Summary ────────────────────────
Values
Name año_viajes
Number of rows 5723606
Number of columns 7
_______________________
Column type frequency:
character 5
POSIXct 2
________________________
Group variables None
── Variable type: character ──────────────────────────────────────────────────
skim_variable n_missing complete_rate min max empty n_unique whitespace
1 ride_id 0 1 8 16 0 5723606 0
2 rideable_type 0 1 11 13 0 3 0
3 start_station_name 868772 0.848 3 64 0 1801 0
4 end_station_name 925008 0.838 3 64 0 1799 0
5 member_casual 0 1 6 6 0 2 0
── Variable type: POSIXct ────────────────────────────────────────────────────
skim_variable n_missing complete_rate min
1 started_at 0 1 2022-08-01 05:00:00
2 ended_at 0 1 2022-08-01 05:05:00
max median n_unique
1 2023-07-31 23:59:56 2023-02-16 13:53:51 4228563
2 2023-08-12 04:53:41 2023-02-16 14:04:56 4238686
Las consultas nos muestra la siguiente información:
Numero de filas: 5723606
Numero de columnas: 7
Filas con valor NA:
start_station_name: 868772, end_station_name: 925008
Columnas con datos completos:
La columna ride_id muestra que no tiene valores duplicados pue tiene 5723606 que es el mismo que el número total de filas.
Nos permitiran realizar consultas útiles en el análisis de datos.
año_viajes$ride_length <- difftime(año_viajes$ended_at, año_viajes$started_at)
glimpse(año_viajes)
Rows: 5,723,606
Columns: 8
$ ride_id <chr> "550CF7EFEAE0C618", "DAD198F405F9C5F5", "E6F2BC47…
$ rideable_type <chr> "electric_bike", "electric_bike", "electric_bike"…
$ started_at <dttm> 2022-08-08 02:34:00, 2022-08-08 19:39:00, 2022-0…
$ ended_at <dttm> 2022-08-08 02:41:00, 2022-08-08 19:53:00, 2022-0…
$ start_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ end_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ member_casual <chr> "casual", "casual", "casual", "casual", "casual",…
$ ride_length <drtn> 7 mins, 14 mins, 11 mins, 15 mins, 5 mins, 13 mi…
Se cambia el tipo de dato de la columna ride_length a númerica para poder realizar análisis posteriores y se verifica el cambio.
año_viajes$ride_length <- round(año_viajes$ride_length, 2)
año_viajes$ride_length <- as.numeric(as.character(año_viajes$ride_length)
)
glimpse(año_viajes_v2)
Rows: 5,721,048
Columns: 13
$ ride_id <chr> "550CF7EFEAE0C618", "DAD198F405F9C5F5", "E6F2BC47…
$ rideable_type <chr> "electric_bike", "electric_bike", "electric_bike"…
$ started_at <dttm> 2022-08-08 02:34:00, 2022-08-08 19:39:00, 2022-0…
$ ended_at <dttm> 2022-08-08 02:41:00, 2022-08-08 19:53:00, 2022-0…
$ start_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ end_station_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ member_casual <chr> "casual", "casual", "casual", "casual", "casual",…
$ ride_length <dbl> 7, 14, 11, 15, 5, 13, 9, 18, 11, 11, 3, 6, 7, 4, …
$ date <date> 2022-08-08, 2022-08-08, 2022-08-08, 2022-08-08, …
$ day_of_week <chr> "lunes", "lunes", "lunes", "lunes", "lunes", "lun…
$ day_of_month <int> 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8…
$ month <dbl> 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8…
$ year <dbl> 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2…
año_viajes $date <- as.Date(date$started_at)
año_viajes <- año_viajes %>% mutate(day_of_week = weekdays(date))
año_viajes <- año_viajes %>% mutate(day_of_month = day(date))
año_viajes <- año_viajes %>% mutate(month = month(date))
año_viajes <- año_viajes %>% mutate(year = year(date))
Se filtran datos que tienen duración del viaje mayor a 0 en un nuevo marco [año_viajes_v2]. Ya que los datos con viaje menor a cero pudieron ser solo pruebas de Cyclistic. Y el nuevo marco esta listo para el análisis de datos.
año_viajes_v2 <- subset(año_viajes, año_viajes$start_station_name != "HQ QR" | año_viajes$ride_length > 0)
skim_without_charts(año_viajes_v2)
── Data Summary ────────────────────────
Values
Name año_viajes_v2
Number of rows 5721048
Number of columns 13
_______________________
Column type frequency:
character 6
Date 1
numeric 4
POSIXct 2
________________________
Group variables None
── Variable type: character ──────────────────────────────────────────────────────────────
skim_variable n_missing complete_rate min max empty n_unique whitespace
1 ride_id 0 1 8 16 0 5721048 0
2 rideable_type 0 1 11 13 0 3 0
3 start_station_name 866214 0.849 3 64 0 1801 0
4 end_station_name 922611 0.839 3 64 0 1799 0
5 member_casual 0 1 6 6 0 2 0
6 day_of_week 0 1 5 9 0 7 0
── Variable type: Date ───────────────────────────────────────────────────────────────────
skim_variable n_missing complete_rate min max median n_unique
1 date 0 1 2022-08-01 2023-07-31 2023-02-16 365
── Variable type: numeric ────────────────────────────────────────────────────────────────
skim_variable n_missing complete_rate mean sd p0 p25 p50 p75
1 ride_length 0 1 18.4 174. -10353. 5.45 9.62 17.0
2 day_of_month 0 1 15.6 8.78 1 8 15 23
3 month 0 1 6.96 2.69 1 5 7 9
4 year 0 1 2023. 0.497 2022 2022 2023 2023
p100
1 51461.
2 31
3 12
4 2023
── Variable type: POSIXct ────────────────────────────────────────────────────────────────
skim_variable n_missing complete_rate min max
1 started_at 0 1 2022-08-01 05:00:00 2023-07-31 23:59:56
2 ended_at 0 1 2022-08-01 05:05:00 2023-08-12 04:53:41
median n_unique
1 2023-02-16 19:02:18 4228480
2 2023-02-16 19:15:23 4238611
De 5723606 filas al inicio de la limpieza quedaron 5721048 al finalizar. Se eliminaron 2558 datos.
Se escribe código que muestre la cantidad total, porcentaje y gráfico de ciclistas por membresia.
año_viajes_v2 %>% count(member_casual) %>% mutate((porcentaje = (n/sum(n))*100))
# A tibble: 2 × 3
member_casual n `(porcentaje = (n/sum(n)) * 100)`
<chr> <int> <dbl>
1 casual 2168089 37.9
2 member 3552959 62.1
año_viajes_v2 %>% count(member_casual) %>% mutate(porcentaje = (n/sum(n))*100) %>%
group_by(member_casual) %>% summarise(porcentaje) %>%
ggplot() +
geom_col(mapping = aes(x=member_casual, y = porcentaje, fill=member_casual)) + labs(title = "Cantidad ciclistas", caption="Datos: Agosto 2022 – Julio 2023")
año_viajes_v2 %>% group_by(member_casual) %>% summarise(total_ciclistas=length(ride_id)) %>% ggplot()+geom_col(mapping = aes(x=member_casual,y= total_ciclistas, fill=member_casual)) + labs(title = "Cantidad ciclistas", caption="Datos: Agosto 2022 – Julio 2023")
Se escribe código que muestre el promedio, máximo y mínimo de un viaje.
summary(año_viajes_v2$ride_length)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-10353.35 5.45 9.62 18.37 17.02 51461.40
51461.40 /60
[1] 857.69
Se escribe código que muestre la duración y el gráfico del viaje por tipo de ciclista por promedio, maximo y mínimo de duración de tiempo.
año_viajes_v2 %>% group_by(member_casual) %>% summarise(tiempo_seg = mean(ride_length))
año_viajes_v2 %>% group_by(member_casual) %>%
summarise(tiempo_seg = mean(ride_length)) %>%
ggplot() + geom_col(mapping = aes(x = member_casual, y = tiempo_seg,fill = member_casual)) +
labs(title = "Tiempo promedio de viaje.", caption="Datos: Agosto 2022 – Julio 2023") +
theme(plot.caption.position = "plot",
plot.caption = element_text(hjust = 1))
aggregate(año_viajes_v2$ride_length ~año_viajes_v2$member_casual, FUN = max)
año_viajes_v2$member_casual año_viajes_v2$ride_length
1 casual 51461.40
2 member 1559.67
51461.40 / 60
[1] 857.69
51461.40 / 1440
[1] 35.73708
1559.67 / 60
[1] 25.9945
1559.67 / 1440
[1] 1.083104
aggregate(año_viajes_v2$ride_length ~año_viajes_v2$member_casual, FUN = min)
año_viajes_v2$member_casual año_viajes_v2$ride_length
1 casual -57.98
2 member -10353.35
10353.35 /60
[1] 172.5558
Se escribe código que muestre la duración promedio por día y el gráfico por tipo de ciclista.
año_viajes_v2 %>%
mutate(day_of_week = wday(started_at, label = TRUE)) %>%
group_by(member_casual, day_of_week) %>%
summarise(porcentaje_seg = (n()/nrow(año_viajes_v2)*100)) %>%
arrange(member_casual, day_of_week) %>%
`summarise()` has grouped output by 'member_casual'. You can override using the
`.groups` argument.
# A tibble: 14 × 3
# Groups: member_casual [2]
member_casual day_of_week porcentaje_viajes
<chr> <ord> <dbl>
1 casual "dom\\." 5.95
2 casual "lun\\." 4.45
3 casual "mar\\." 4.44
4 casual "mié\\." 4.57
5 casual "jue\\." 5.10
6 casual "vie\\." 5.80
7 casual "sáb\\." 7.59
8 member "dom\\." 6.82
9 member "lun\\." 8.66
10 member "mar\\." 9.61
11 member "mié\\." 9.88
12 member "jue\\." 10.0
13 member "vie\\." 9.02
14 member "sáb\\." 8.09
año_viajes_v2 %>%
mutate(day_of_week = wday(started_at, label = TRUE)) %>%
group_by(member_casual, day_of_week) %>%
summarise(porcentaje_seg = (n()/nrow(año_viajes_v2)*100)) %>%
arrange(member_casual, day_of_week) %>%
ggplot(aes(x = day_of_week, y = porcentaje_seg, fill = member_casual)) +
geom_col(position = "dodge") +
labs(title = "Duración promedio por día", caption="Datos: Agosto 2022 – Julio 2023"
) + theme(plot.caption.position = "plot", plot.caption = element_text(hjust = 1))
Se escribe código que muestre la duración promedio, la cantidad de viajes por dia y el gráfico por tipo de ciclista.
año_viajes_v2 %>%
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)
member_casual weekday number_of_rides average_duration
<chr> <ord> <int> <dbl>
1 casual "dom\\." 340123 33.0
2 casual "lun\\." 254593 27.7
3 casual "mar\\." 254166 24.9
4 casual "mié\\." 261400 24.5
5 casual "jue\\." 291668 23.9
6 casual "vie\\." 331726 27.2
7 casual "sáb\\." 434413 32.4
8 member "dom\\." 390183 13.7
9 member "lun\\." 495243 11.8
10 member "mar\\." 549586 11.9
11 member "mié\\." 564999 11.8
12 member "jue\\." 573938 11.9
13 member "vie\\." 516168 12.4
14 member "sáb\\." 462842 13.9
año_viajes_v2 %>%
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) %>%
ggplot(aes(x = weekday, y = number_of_rides, fill = member_casual)) +
geom_col(position = "dodge") +
labs(title = "Viajes promedio por día", caption="Datos: Agosto 2022 – Julio 2023"
) + theme(plot.caption.position = "plot", plot.caption = element_text(hjust = 1))
año_viajes_v2 %>%
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) %>%
ggplot(aes(x = weekday, y = average_duration, fill = member_casual)) +
geom_col(position = "dodge") +
labs(title = "Duración promedio por día", caption="Datos: Agosto 2022 – Julio 2023"
) + theme(plot.caption.position = "plot", plot.caption = element_text(hjust = 1))
Se escribe código que cuente la cantidad y tipo de bicicletas.
año_viajes_v2 %>% count(rideable_type) %>% mutate((porcentaje= (n/sum(n))*100))
# A tibble: 3 × 3
rideable_type n `(porcentaje = (n/sum(n)) * 100)`
<chr> <int> <dbl>
1 classic_bike 2484277 43.4
2 docked_bike 128904 2.25
3 electric_bike 3107867 54.3
año_viajes_v2 %>% count(rideable_type) %>% mutate(porcentaje = (n/sum(n))*100) %>%
group_by(rideable_type) %>% summarise(porcentaje) %>%
ggplot() +
geom_col(mapping = aes(x= rideable_type, y = porcentaje, fill = rideable_type )) + labs(title = "Tipo de bicicletas", caption="Datos: Agosto 2022 – Julio 2023") + theme(plot.caption.position = "plot", plot.caption = element_text(hjust = 1))
Se escribe código que cuenta la duración promedio y tipo de bicicletas.
año_viajes_v2 %>%
group_by(rideable_type, member_casual) %>%
summarise(Average_ride_length = mean(ride_length))
rideable_type member_casual Average_ride_length
<chr> <chr> <dbl>
1 classic_bike casual 29.1
2 classic_bike member 13.8
3 docked_bike casual 153.
4 electric_bike casual 14.7
5 electric_bike member 11.1
año_viajes_v2 %>%
group_by(rideable_type, member_casual) %>%
summarise(Average_ride_length = mean(ride_length)) %>%
ggplot(aes(x=rideable_type, y=Average_ride_length, fill=member_casual)) +
geom_col(position = "dodge") + labs(title="Uso promedio por tipo de bicicleta.") +
labs(title = "Viajes por tipo de bicicleta", caption="Datos: Agosto 2022 – Julio 20
23") + theme(plot.caption.position = "plot", plot.caption = element_text(hjust = 1
)
Al realizar el análisis de datos sobre la tarea empresarial para buscar en qué se diferencian los socios anuales y los ciclistas ocasionales con respecto al uso de las bicicletas realice varios procesos siguiendo el orden de las etapas del proceso de análisis de datos y obtuve los siguientes resultados:
o Revise que los datos cumplieron con los requisitos de integridad de los datos al ser confiables, originales, integrales, actualizados y citados.
o Elección del R Studio para realizar el análisis y la configración del entorno al crear el proyecto, cargar las librerias necesarias y los archivos de datos de los ciclistas de los 12 últimos meses que van de Agosto de 2022 a Julio de 2023.
o Ejecución de la función glimpse en cada archivo de los ciclistas para validar que todos los archivos contengan el mismo número, tipo de datos y nombre de columna. Un archivo mostro diferencia con el tipo de datos en dos columnas respecto a los demas archivos y se realizo el cambio de tipo de datos en estas columnas.
o Una vez comprobe que todos los archivos tenían el mismo tipo de datos, los uni creando un dataframe.
o Elimine las columnas: start_lat, end_lat, start_lng, end_lng, start_station_id, end_station_id ya que pueden interferir con la política de privacidad y no resultan útiles para el análisis según mi criterio
o Revise la estructura resumida del marco de datos para saber si tenia datos repetidos o nulos con la funcion skim(); no contenia datos duplicados y si muchos nulos pero decidí dejarlos ya que pieno que no afectan los resultados del análisis.
o Agregue la columna ride_length que muestra lo que tarda el ciclista desde que tomar la bicicleta en la estación de inicio hasta que la regresa a la estación; servira para realizar consultas posteriores.
o Agregue la columna date que salio de la columna started_at y tambien las columnas day_of_week, day_of_month, month y year que salieron de la columna date para realizar consultas posteriores.
o Filtre algunas filas que contenían datos con valores negativos en cuanto al tiempo y que podrian haber sido solo pruebas realizadas por la empresa y cree un nuevo marcho para realizar el análisis de datos.
• Casuales Total: 2168089 Porcentaje: 37.9%
• Miembros Total: 3552959 Porcentaje: 62.1%
• Promedio Total: 18 min.
• Mínimo Total: -10353 min.
• Máximo Total: 51461 min. , 857 horas
• Promedio
A pesar de que los ciclistas con membresia anual son mas, tienden a usar menos tiempo las bicicletas que los casuales que las usan mas del doble de tiempo que estos.
Casual: 28 minutos
Anual: 12 minutos
• Viaje mas largo
Casual: 51461 minutos, 857 horas, 35 días Anual: 1559 minutos, 25 horas, 1 días
• Viaje mas corto:
Casual: -57 minutos Anual: -10353 minutos, -172 horas
Se puede ver que los ciclistas con membresia casual tienen mas actividad los días sabado y domingo mientras que los ciclistas com membresia anual tienen menos actividad el día domingo.
Los ciclistas con membresia casual tienen menos viajes que los ciclistas con membresia anual pero la duración de sus viajes es mas del doble que los otros.
• Clasic Total: 2484277 Porcentaje: 43.4%
• Docked Total: 128904 Porcentaje: 2.25%
• Electric bike Total: 3107867 Porcentaje: 54.3%
Los ciclistas con membresia casual que usan tanto la bicicleta clásica como la eléctrica hacen viajes mas largos que los ciclistas con membresia anual.
Despues de la etapa de análisis recomedaría que se realizaran las siguientes acciones.
o Sería aconsejable ofrecer a los ciclistas con membresia casual a cambiar a la membresía anual con descuentos preferencial dependiendo de ciertas distancias recorridas.
o Ambos ciclistas prefiern el uso de biciletas eléctricas por lo cual se recomienda adquirir mas de ellas.
o Hacer la propaganda los fines de semana que es cuando estan más activos los ciclistas casuales.