RのWeb制作

Webサービス制作のための技術情報を。データ分析(Python、機械学習コンペ他)や自作野球ゲームMeisyoのこと中心。

データサイエンス 監督たちの甲子園 データ分析

監督たちの甲子園(v1.3.5) 新規ユーザー分析

投稿日:2025年3月30日 更新日:

私は運営するゲームの分析を日常的に行い、機能の改善を行っています。
元々ゲーム運営のアナリスト(コンサルタント)をしていたので、ゲームの分析はチョットワカルかもしれません。

今回は、ゲームの状況をかんたんに確認するために、新規ユーザーの継続率を分析していきます。

前提

・Unity Analyticsで分析した結果です。
Unity Analytics > SQL データエクスプローラーを利用しています。
SQLの種類はPostgreSQLベースに見えます。

・全ユーザーは含んでいないログです。
(上手く取れないユーザーがかなりいる模様…)

・SQLコードを公開します。
自身のゲームの分析などにご自由にお使いください。

分析したゲームはこちら

監督たちの甲子園 世紀の逆転劇

新規ユーザーの分析

まず、分析するにあたって対象ユーザーと指標を確認しましょう。

対象ユーザー

新規ユーザーとは、ゲームを開始してすぐのユーザーのことです。
※対して、既存ユーザーはゲームを開始して何日か経過して継続しているユーザーのことを言います。

指標:継続率

継続率は、対象となるユーザーが、対象となる経過日(24時間以内)にログインしている割合を確認します。

継続とは、
DAY1であれば、新規登録後24~48時間にログインしている人をいいます。
DAY3であれば、新規登録24*3~24*(1+3)時間にログインしている人、
DAY7であれば、新規登録24*7~24*(1+7)時間にログインしている人、
DAY14であれば、新規登録24*28~24*(1+14)時間にログインしている人、
DAY28であれば、新規登録24*28~24*(1+28)時間にログインしている人です。
※DAY1, 3, 7, 14, 28の日の区切りはゲームや会社によって変わります。

この指標は「毎日ログインすることが当たり前のゲーム」で採用されやすいです。
毎日プレイすることが必須ではない場合、以下の継続率(Week版)のような指標を入れてみることがあります。

指標:継続率(Week版)

継続率(Wide版)は、継続の判定幅を広くした継続率のことです。

継続(Week版)とは、
DAY1であれば、新規登録後24~24*(1+7)時間にログインしている人をいいます。
つまり、1日後から1週間以内にログインしている人を示します。

この指標は「毎日ログインすることが当たり前ではないゲーム」で採用されます。
「1週間に1回は触ってもらえるよね」ってことです。
これは分析の都合上、「ユーザーがゲームから離脱したかどうか」を厳密に判定できないため、かなり幅を持たせて分析をしています。
分析するサービスによって変わるので、調整して使ってみてください。

分析:バージョン別継続率

それでは、ゲームの分析を行ってみます。

ゲームはバージョンアップにより内容が様変わりするため、「継続率を取るにはバージョン別が良いだろう」ということでバージョン別に分析を行います。
加えて、特定のプラットフォーム(iOS/Android/PCなど)に異常がないことを確認するために、プラットフォーム別にも分析します。「プラットフォームの継続率が大きく違う」ことは、異常があると判断できます。

分析からわかること1

では、継続率を見ていきましょう。
初期バージョン(v1.0、v1.1、v1.2)はそれほど指標が変わりません。

テコ入れしたv1.3_1は指標が大きく改善しています。これは良いアップデートだったと言えるでしょう。
ただ、さらにテコ入れしたv1.3_2は初期バージョンより下がっています。これはよろしくないので、元に戻しましょう。

という、数字からゲーム内に何が起こっているかを想像しながら見ていく必要があります。

分析からわかること2

では、プラットフォーム別に見ていきましょう。

・iOSが良さげかも?
・Androidは要改善
・PCは人がいない
※加えて、完全オフラインではログが取れない仕組みなので実態が不明なユーザーもいます。

こちらの数値と外部データを見比べてみると面白いことがわかります。
・App Store(iOS)とGoogle Play(Android)の登録数から、ログが取れないユーザーがいそう。
・App Storeのアプリ保持数は200超だが、Google Playは100いくかどうか。
Google Playユーザーのほうがアプリを消す傾向にあると言えるでしょう。このゲームは400MB近く容量ありますからね…。

分析からわかること3

継続率と、継続率(Week版)に大きな(20%以上の)差があります。特にDAY3以降ですね。

1日後継続しない人は、1週間にわたって観察してもほぼ継続しないことが読み取れます。DAY1とDAY1(WEEK版)の数値がほぼ同じですし。
ただ、3日後以降はユーザーは思い思いにログインしているようです。なぜなら、DAY3の1日間だけログイン割合より、DAY3~10の間のログイン割合が大きく伸びているからです。
つまり、平均的なユーザーはこのゲームに対してどのような接し方をしているか推察できます。

このデータから追加で、深掘りとして「毎日ログインしているひと」「たまにログインしているひと」の人数を確認して、それぞれに合わせた施策を打つ等を考えていけますね。

分析コード
当ゲームはバージョンの記載方法にCLIENT_VERSION=「X.X.X」を採用しているため、複数バージョンをVERSION_GROUPにまとめています。
ある程度ユーザー数がいないと分析できないので、複数バージョンをまとめるようにしてください。

-- ユーザーIDごとのゲーム開始時間
WITH user_first_start AS (
  SELECT 
    USER_ID
    ,time_start
    ,PLATFORM
    -- バージョンごとに切り分け
    ,CASE
        WHEN CLIENT_VERSION LIKE '1.0.%' THEN 'v1.0.X'
        WHEN CLIENT_VERSION LIKE '1.1.%' THEN 'v1.1.X'
        WHEN CLIENT_VERSION LIKE '1.2.%' THEN 'v1.2.X'
        WHEN CLIENT_VERSION LIKE '1.3.%' THEN 
            CASE
                WHEN CLIENT_VERSION <= '1.3.3' THEN 'v1.3_1'
                WHEN CLIENT_VERSION <= '1.3.5' THEN 'v1.3_2'
                ELSE 'v3_3'
                END
        ELSE 'others'
    END AS VERSION_GROUP
  FROM
    (
        SELECT 
            USER_ID
            ,EVENT_TIMESTAMP AS time_start
            ,PLATFORM
            ,CLIENT_VERSION
            ,ROW_NUMBER() OVER (PARTITION BY USER_ID ORDER BY EVENT_TIMESTAMP ASC) AS rn
        FROM
            EVENTS
    ) AS t
  WHERE
    rn = 1

)
-- 継続率
, user_retention AS (
  SELECT
    fs.USER_ID
    ,fs.time_start
    ,fs.PLATFORM
    ,fs.VERSION_GROUP
    -- 通常判定版(1day内)
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 1, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (1 + 1), fs.time_start)
         THEN 1 ELSE 0 END) AS day1
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 3, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (1 + 3), fs.time_start)
         THEN 1 ELSE 0 END) AS day3
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 7, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (1 + 7), fs.time_start)
         THEN 1 ELSE 0 END) AS day7
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 14, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (1 + 14), fs.time_start)
         THEN 1 ELSE 0 END) AS day14
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 28, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (1 + 28), fs.time_start)
         THEN 1 ELSE 0 END) AS day28
    -- 判定広め版(1week内)
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 1, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (7 + 1), fs.time_start)
         THEN 1 ELSE 0 END) AS day1_w
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 3, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (7 + 3), fs.time_start)
         THEN 1 ELSE 0 END) AS day3_w
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 7, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (7 + 7), fs.time_start)
         THEN 1 ELSE 0 END) AS day7_w
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 14, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (7 + 14), fs.time_start)
         THEN 1 ELSE 0 END) AS day14_w
    ,MAX(CASE WHEN
          e.EVENT_TIMESTAMP > TIMESTAMPADD(HOUR, 24 * 28, fs.time_start)
          AND e.EVENT_TIMESTAMP <= TIMESTAMPADD(HOUR, 24 * (7 + 28), fs.time_start)
         THEN 1 ELSE 0 END) AS day28_w
  FROM
    user_first_start AS fs
  INNER JOIN
    EVENTS AS e
  ON
    fs.USER_ID = e.USER_ID
  GROUP BY
    1, 2, 3, 4
)

-- 日別分析
SELECT
  VERSION_GROUP
  ,PLATFORM
  ,DATE(MIN(time_start)) AS date_min
  ,DATE(MAX(time_start)) AS date_max
  ,COUNT(*) AS count_uu
  ,SUM(day1) / COUNT(*) AS rate_day1
  ,SUM(day3) / COUNT(*) AS rate_day3
  ,SUM(day7) / COUNT(*) AS rate_day7
  ,SUM(day14) / COUNT(*) AS rate_day14
  ,SUM(day28) / COUNT(*) AS rate_day28
  ,SUM(day1_w) / COUNT(*) AS rate_day1_w
  ,SUM(day3_w) / COUNT(*) AS rate_day3_w
  ,SUM(day7_w) / COUNT(*) AS rate_day7_w
  ,SUM(day14_w) / COUNT(*) AS rate_day14_w
  ,SUM(day28_w) / COUNT(*) AS rate_day28_w
FROM
  user_retention
GROUP BY
  1, 2
ORDER BY
  1, 2;

さいごに

今日はかんたんに、新規ユーザーの継続率からゲームの現状を分析しました。
「もっと知りたい」「○○ってどう分析すればいいの?」というコメントをいただければ、記事を書いていきたいと思います。
ぜひコメントくださいませ。( ^^)/

-データサイエンス, 監督たちの甲子園, データ分析

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

ログがサービス改善の命

Meisyoでは常にログを取って、「ユーザがどこで困ってそうかな」を探し続けています。 探す方法はいたって簡単。 (何か問題があると考えて)ログを眺める 今回のアップデートでは、アイテムの購入数を選択 …

【教材紹介】Interpretable Machine Learning(邦訳:解釈可能な機械学習)

機械学習の解釈可能性については、近年さらに重要視されています。 なぜでしょうか?それは、この書籍に記載されています。 このWebサイト(なんと無料!)では、説明性の性質の違いや、人間が考える良い説明と …

[Meisyo+] データ分析その1 能力値ベースの打率予測

監督視点の野球ゲーム Meisyo+でデータが貯まってきたので、打率の予測をしてみました。 打率は高ければ高いほどいいですが、実際のところどの能力値を重要視していいかわかりません。 そのため、今回はど …

Pandas DataFrameでの表示列・行をすべて表示する(表示制限を解除する)

Jupyter NotebookでPandasのDataFrameを表示する際、行数・列数が多すぎると省略されてしまう場合があります。 制限を解除しましょう。 pd.set_option(‘displ …

[Meisyo]ゲームのUIを改善し続ける意味とは

1ヶ月に3回はUIが変わっているMeisyo。 何故変え続けているのか。 説明しよう! 今悪いポイント 簡単に言うと新規登録ユーザーさんが定着しない! チュートリアルでも最終ステップまでの到達率が75 …