ケーススタディー:自転車シェアリングサービスを成功させる
Googleデータアナリティクス プロフェッショナルのケーススタディーとして、
架空の自転車シェアリングサービスを成功させる=利潤を向上させる方法をデータ分析の手法を用いて提案するという課題に取り組んでいます。今回は分析プロセスの内問いかけ、準備、処理、分析、共有、行動の内分析の中ほどまでが完了したので、その内容を記録してみました。
シナリオ
ケーススタディーに取り組む人は、架空の自転車シェアリング会社:サイクリスティック社で働いてます。上司のマーケティングディレクターは会社の将来の成功のため、年間メンバーシップを持つユーザーを増やしたいと考えています。そのため、データ分析を行うチームはカジュアルユーザーを年間メンバーへ移行を推進する方法をデータのインサイト・可視化情報から考案する必要があります。
サイクリスティック社は2016年から自転車シェアリング会社に取り組んでいて、大都市シカゴに位置情報システムが搭載された自転車5824台を692箇所のドックに展開しています。サイクスティック社のマーケティング戦略は、幅広いユーザーが利用できるという認知を広めることです。特に料金プランを充実させていて、1回のみの使用ができるカジュアルユーザー・1年間終日利用ができる年間メンバーシップの2つの料金プランがあります。
問いかけ
問いかけの段階では、まずシナリオに提示された事業タスクを明確にします:
①カジュアルユーザー・年間メンバーとで自転車の利用法に違いがあるか?
②カジュアルユーザーのなかでも、カジュアルユーザー→年間メンバーへと移行する理由は何か?
③サイクスティック社がカジュアルユーザー→年間メンバーへの移行を推進するためには、どのようにデジタルメディアを活用できるか?
今回は、①の問いかけに集中して取り組みます。次の分析プロセスに進むためには、レポートに掲載するべき次のタスクを明確にします:
1、事業タスクを明確にする
2、利用できるデータソースを明確にする
3、データクリーニング・加工が行われている場合はそのドキュメントを残す
4、分析結果を要約する
5、キーとなる情報を裏付ける・証明する可視化情報を作成する
6、分析をした結果、①に対しての提案を3つ挙げる
準備
レポートに書くべきことが明確になったら、次は準備に取り掛かります。
まず12ヶ月分の他社の自転車シェアリング会社のデータをDLし、データ分析に利用できる状態にします。
1、データのソースはどこにあるか
2、データの構造はどうなっているか
3、バイアス・信用性の問題はないか(ROCCCをチェック)
4、ライセンスと知財・著作権、データ上の個人情報・アクセシビリティーなどの問題はないか
5、データ完全性を確保したか
6、データは問いかけで定めた事業タスクに役立つか
7、その他、データそのものに問題はないか
- 今回は分析に用いるデータとして、divvy社(※架空のデータです)の2022年3月 - 2023年2月までの自転車シェアリング事業のデータを利用しました:
処理
データの準備が完了したら、次はデータの処理を開始します。
この段階でデータの処理と分析にどのようなツールを使うか・データのクリーニングを完了しているかを確認します。今回はデータの処理にRStudioを使用します。12ヶ月分のデータを結合したデータフレームを作成する他、分析に用いる新しい指標や定性データを追加します。
- divvy社の2022年3月 - 2023年2月までの自転車シェアリング事業のデータを1つのcsvファイルに統合
- 利用時間(ride_length)という定量データを追加(利用終了時間 - 利用開始時間を計測する)
- date, month, day, day_for_weekという日付に関係する定性データを追加(2022-03 ~ 2023-02)
データを1つのデータフレームに纏める
library(tidyverse) #データラングリング
library(lubridate) #時刻データを扱うメソッド
library(ggplot2) #可視化
setwd("C:\\Users\\user\\Desktop\\Data_Learning\\2023_share_cycling")
data_202203 <- read.csv("202203-divvy-tripdata.csv")
data_202204 <- read.csv("202204-divvy-tripdata.csv")
data_202205 <- read.csv("202205-divvy-tripdata.csv")
data_202206 <- read.csv("202206-divvy-tripdata.csv")
data_202207 <- read.csv("202207-divvy-tripdata.csv")
data_202208 <- read.csv("202208-divvy-tripdata.csv")
data_202209 <- read.csv("202209-divvy-publictripdata.csv")
data_202210 <- read.csv("202210-divvy-tripdata.csv")
data_202211 <- read.csv("202211-divvy-tripdata.csv")
data_202212 <- read.csv("202212-divvy-tripdata.csv")
data_202301 <- read.csv("202301-divvy-tripdata.csv")
data_202302 <- read.csv("202302-divvy-tripdata.csv")
#bind_rowsを使って12ヶ月分のデータを1つのデータフレームに纏める
data_all <- bind_rows(data_202203, data_202204, data_202205, data_202206, data_202207, data_202208, data_202209, data_202210, data_202211, data_202212, data_202301, data_202302)
View(data_all)
colnames(data_all)
str(data_all)
#自転車ID(ride_id)を文字列データに変換
data_all <- mutate(data_all, ride_id = as.character(ride_id))
#分析に使わないデータを削除する(start_lat, start_lng, end_lat, end_lng)
data_all <- data_all %>%
select(-c(start_lat, start_lng, end_lat, end_lng))
データのクリーンアップを開始
#データの内容を確認
colnames(data_all) #データのコラム名
nrow(data_all) #データフレームの行数
dim(data_all) #データフレームの次元数
head(data_all) #最初の5行を開始
str(data_all) #データコラムのデータ型を表示する
summary(data_all) #定量データの要約統計量を表示
# 時系列データをクリーンアップ・文字列→時刻に変換、新しい時刻データを追加
# https://www.statmethods.net/input/dates.html more on date formats in R found at that link
data_all$date <- as.Date(data_all$started_at) #The default format is yyyy-mm-dd
data_all$month <- format(as.Date(data_all$date), "%m")
data_all$day <- format(as.Date(data_all$date), "%d")
data_all$year <- format(as.Date(data_all$date), "%Y")
data_all$day_of_week <- format(as.Date(data_all$date), "%A")
#乗車時間のデータ(ride_length)を追加
data_all$ride_length <- difftime(data_all$ended_at, data_all$started_at)
#乗車時間のデータ(ride_length)を定量データに変換する
is.factor(data_all$ride_length)
data_all$ride_length <- as.numeric(as.character(data_all$ride_length))
is.numeric(data_all$ride_length)
str(data_all)
データの統計解析
#乗車時間のデータの記述統計
mean(data_all$ride_length) #平均
median(data_all$ride_length) #中央値
max(data_all$ride_length) #最大値
min(data_all$ride_length) #最小値
#summary()で要約統計量を表示する
summary(data_all$ride_length)
#年間ユーザー・カジュアルユーザーを比較する
#最小が負の値 → 負の値を0に統一する方法を考える
aggregate(data_all$ride_length ~ data_all$member_casual, FUN = mean)
aggregate(data_all$ride_length ~ data_all$member_casual, FUN = median)
aggregate(data_all$ride_length ~ data_all$member_casual, FUN = max)
aggregate(data_all$ride_length ~ data_all$member_casual, FUN = min)
#週ごとの年間ユーザー・カジュアルユーザーを比較する
aggregate(data_all$ride_length ~ data_all$member_casual + data_all$day_of_week, FUN = mean)
#週を月曜からの順にする
data_all$day_of_week <- ordered(data_all$day_of_week, levels=c("月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日", "日曜日"))
aggregate(data_all$ride_length ~ data_all$member_casual + data_all$day_of_week, FUN = mean)
#週ごとの利用車種を分析する
data_all %>%
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)
データの可視化
#週ごとの利用車数(メンバー・カジュアルの比較)を可視化する
data_all %>%
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")
#週ごとの利用時間の平均(メンバー・カジュアルの比較)を可視化する
data_all %>%
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")
可視化資料の共有
週日ごとの利用車数(メンバー・カジュアルの比較)を可視化すると、次の傾向が分かります。
年間メンバーの利用者は、平日になるとカジュアルユーザーの1.5~2.0倍ほどの水準となります。利用者数に着目すると、年間メンバー・カジュアルユーザーの違いは平日に利用者数が増えるか・減るかという利用法の違いがあることが明らかになります。
一方、週日ごとの利用時間の平均(メンバー・カジュアルの比較)を可視化すると次の傾向が分かります。
カジュアルユーザーは年間メンバーに比べ、利用時間の平均が2.0~3.0倍程となります。特に休日と月曜・金曜にこの傾向が高いようです。利用時間の平均に着目すると、年間メンバー・カジュアルユーザーには利用時間が倍以上、特に休日に顕著になるという違いがあります。
これからの課題
#年間ユーザー・カジュアルユーザーを比較する
#最小が負の値 → 負の値を0に統一する方法を考える
aggregate(data_all$ride_length ~ data_all$member_casual, FUN = mean)
aggregate(data_all$ride_length ~ data_all$member_casual, FUN = median)
aggregate(data_all$ride_length ~ data_all$member_casual, FUN = max)
aggregate(data_all$ride_length ~ data_all$member_casual, FUN = min)
- 乗車時間のデータを見てみると、最小値が負の値になるケースがある=値が矛盾するバッドデータが存在していることが分かりました。次回はバッドデータを除外し、より正確な分析をしたうえで可視化資料を制作したいと思います。
- 「カジュアルユーザー・年間メンバーとで自転車の利用法に違いがあるか検定する」という事業タスクを完成させるためには、2つの可視化資料だけでは心もとないように思えます。次回は、データ探索の手法でより説得力のある可視化資料を制作したいと思います。具体的には、利用法の違いを3つ以上指摘することを目指します。