この記事では、Google Playレビューを使って、レビュー件数や評価スコアの推移をPlotlyで可視化する方法を解説します。
日次・月次のレビュー件数、平均スコア、星評価の構成比、アプリバージョン別の評価傾向をグラフ化することで、アップデートやイベント後にユーザー評価がどのように変化したかを確認しやすくなります。
本記事では、前回の記事で取得したGoogle PlayレビューCSVを使い、分析しやすい形に集計してからPlotlyで可視化します。
この記事でできること
- Google PlayレビューCSVを読み込んで日付列を整形する
- 日次・月次のレビュー件数を集計する
- 平均スコアの推移を確認する
- 星評価の構成比を100%積み上げグラフで可視化する
- アプリバージョン別にレビュー件数や評価傾向を見る
- レビュー件数・平均スコア・星評価構成比を組み合わせて評価変動を読み解く
想定読者
- Google PlayレビューをPythonで可視化したい方
- レビュー件数や評価スコアの推移を時系列で確認したい方
- アップデート前後で評価が変化したかを見たい方
- Plotlyでインタラクティブなグラフを作りたい方
- レビュー分析記事やダッシュボードの素材を作りたい方
事前準備
この記事では、Google Playレビューを取得済みで、CSVファイルとして保存されている前提で進めます。レビュー取得がまだの場合は、先に以下の記事を確認してください。
Google Playのデータ取得方法まとめ|google-play-scraperでアプリ情報・レビューを取得する
今回使う主な列は以下です。
| 列名 | 内容 |
|---|---|
content | レビュー本文 |
score | 星評価 |
at | レビュー投稿日 |
reviewCreatedVersion | レビュー投稿時のアプリバージョン |
thumbsUpCount | 参考になった数 |
過去のコードや取得方法によっては、バージョン列が appVersion という名前になっている場合があります。本記事では、基本的に reviewCreatedVersion を使う想定で整理します。
使用ライブラリ
可視化には、pandasとPlotlyを使います。
pip install -U pandas plotlyPlotlyは、拡大・縮小、ホバー表示、凡例のON/OFFなどができるインタラクティブなグラフを作れるライブラリです。時系列グラフや構成比グラフを確認する際に便利です。
CSVを読み込んで日付列を整える
まず、取得済みのレビューCSVを読み込みます。ここでは、前回記事で保存した reviews_genshin_paged.csv を例にします。
import pandas as pd
csv_path = "reviews_genshin_paged.csv"
df = pd.read_csv(csv_path)
df["at"] = pd.to_datetime(df["at"], errors="coerce")
df = df.dropna(subset=["at", "score"]).copy()
df["date"] = df["at"].dt.date
df["month"] = df["at"].dt.to_period("M").dt.to_timestamp()
print(df[["content", "score", "at", "date", "month"]].head())
print("rows:", len(df))at はレビュー投稿日です。日次集計には date、月次集計には month を使います。
レビュー件数と平均スコアの推移を可視化する
まずは、レビュー件数と平均スコアの推移を可視化します。レビュー件数はユーザー反応の量、平均スコアは評価の方向性を見るための基本指標です。
レビュー件数が増えた時期に平均スコアも変化している場合、アップデート、イベント、不具合、キャンペーンなどの影響が出ている可能性があります。
日次では細かい変化を確認しやすく、月次では長期的な傾向を把握しやすくなります。
import plotly.graph_objects as go
daily_summary = (
df.groupby("date")
.agg(
review_count=("score", "size"),
avg_score=("score", "mean"),
)
.reset_index()
)
monthly_summary = (
df.groupby("month")
.agg(
review_count=("score", "size"),
avg_score=("score", "mean"),
)
.reset_index()
)
fig_trend = go.Figure()
fig_trend.add_trace(go.Bar(
x=daily_summary["date"],
y=daily_summary["review_count"],
name="日次レビュー件数",
yaxis="y1",
visible=True,
))
fig_trend.add_trace(go.Scatter(
x=daily_summary["date"],
y=daily_summary["avg_score"],
name="日次平均スコア",
mode="lines+markers",
yaxis="y2",
visible=True,
))
fig_trend.add_trace(go.Bar(
x=monthly_summary["month"],
y=monthly_summary["review_count"],
name="月次レビュー件数",
yaxis="y1",
visible=False,
))
fig_trend.add_trace(go.Scatter(
x=monthly_summary["month"],
y=monthly_summary["avg_score"],
name="月次平均スコア",
mode="lines+markers",
yaxis="y2",
visible=False,
))
fig_trend.update_layout(
title="レビュー件数と平均スコア推移(日次・月次切り替え)",
xaxis_title="日付 / 月",
yaxis=dict(
title="レビュー件数",
side="left",
),
yaxis2=dict(
title="平均スコア",
overlaying="y",
side="right",
range=[1, 5],
),
template="plotly_white",
height=700,
updatemenus=[
{
"buttons": [
{
"label": "日次",
"method": "update",
"args": [
{"visible": [True, True, False, False]},
{"title": "レビュー件数と平均スコア推移(日次)"},
],
},
{
"label": "月次",
"method": "update",
"args": [
{"visible": [False, False, True, True]},
{"title": "レビュー件数と平均スコア推移(月次)"},
],
},
],
"direction": "right",
"x": 0.5,
"xanchor": "center",
"y": 1.15,
"yanchor": "top",
}
],
)
fig_trend.show()
fig_trend.write_html(
"plot_review_trend_switch.html",
include_plotlyjs="cdn",
full_html=True,
)レビュー件数が少ない日は、1件のレビューで平均スコアが大きく変動します。そのため、日次グラフでは細かな変化を見つつ、月次グラフで長期傾向を確認するのがおすすめです。
星評価の構成比を100%積み上げで可視化する
平均スコアだけでは、低評価と高評価の内訳が見えにくい場合があります。そこで、星1〜星5の構成比を100%積み上げ棒グラフで可視化します。
たとえば、平均スコアが同じでも、星3が多い安定型なのか、星1と星5に分かれる賛否両論型なのかで、読み取り方は変わります。
def make_score_ratio(df: pd.DataFrame, period_col: str) -> pd.DataFrame:
score_counts = (
df.groupby([period_col, "score"])
.size()
.unstack(fill_value=0)
)
for score in [1, 2, 3, 4, 5]:
if score not in score_counts.columns:
score_counts[score] = 0
score_counts = score_counts[[1, 2, 3, 4, 5]]
score_ratio = score_counts.div(score_counts.sum(axis=1), axis=0) * 100
return score_ratio.reset_index()
daily_ratio = make_score_ratio(df, "date")
monthly_ratio = make_score_ratio(df, "month")
fig_ratio = go.Figure()
for score in [1, 2, 3, 4, 5]:
fig_ratio.add_trace(go.Bar(
x=daily_ratio["date"],
y=daily_ratio[score],
name=f"★{score}",
visible=True,
))
for score in [1, 2, 3, 4, 5]:
fig_ratio.add_trace(go.Bar(
x=monthly_ratio["month"],
y=monthly_ratio[score],
name=f"★{score}",
visible=False,
))
fig_ratio.update_layout(
barmode="stack",
title="星評価構成比(日次・月次切り替え)",
xaxis_title="日付 / 月",
yaxis_title="構成比(%)",
yaxis=dict(range=[0, 100]),
template="plotly_white",
height=600,
updatemenus=[
{
"buttons": [
{
"label": "日次",
"method": "update",
"args": [
{"visible": [True] * 5 + [False] * 5},
{"title": "星評価構成比(日次)"},
],
},
{
"label": "月次",
"method": "update",
"args": [
{"visible": [False] * 5 + [True] * 5},
{"title": "星評価構成比(月次)"},
],
},
],
"direction": "right",
"x": 0.5,
"xanchor": "center",
"y": 1.15,
"yanchor": "top",
}
],
)
fig_ratio.show()
fig_ratio.write_html(
"plot_score_ratio_switch.html",
include_plotlyjs="cdn",
full_html=True,
)バージョン別のレビュー件数を可視化する
Google Playレビューには、レビュー投稿時のアプリバージョンが含まれる場合があります。バージョン別にレビュー件数を見ることで、特定バージョンでレビューが増えていないかを確認できます。
まず、バージョン列を整えます。取得データによっては reviewCreatedVersion ではなく appVersion という列名になっている場合があるため、どちらにも対応できるようにします。
version_col = None
for candidate in ["reviewCreatedVersion", "appVersion"]:
if candidate in df.columns:
version_col = candidate
break
if version_col is None:
raise ValueError("アプリバージョン列が見つかりません。")
df["version"] = df[version_col].fillna("不明")
version_counts = (
df.groupby("version")
.size()
.reset_index(name="review_count")
.sort_values("review_count", ascending=False)
)
print(version_counts.head(20))バージョンが空のレビューは、ここでは「不明」として扱っています。古いレビューや投稿環境によっては、バージョン情報が入っていない場合があります。
import plotly.express as px
top_versions = version_counts.head(20)["version"].tolist()
df_ver = df[df["version"].isin(top_versions)].copy()
ver_daily = (
df_ver.groupby(["date", "version"])
.size()
.reset_index(name="review_count")
)
fig_ver_count = px.line(
ver_daily,
x="date",
y="review_count",
color="version",
title="バージョン別レビュー件数推移",
labels={
"date": "日付",
"review_count": "レビュー件数",
"version": "アプリバージョン",
},
height=600,
)
fig_ver_count.update_layout(template="plotly_white")
fig_ver_count.show()
fig_ver_count.write_html(
"plot_version_count.html",
include_plotlyjs="cdn",
full_html=True,
)バージョン別の星評価構成比を見る
次に、バージョン別に星評価の構成比を確認します。特定バージョンで低評価が増えている場合、不具合、仕様変更、バランス調整、UI変更などが影響している可能性があります。
score_ver = (
df_ver.groupby(["version", "score"])
.size()
.unstack(fill_value=0)
)
for score in [1, 2, 3, 4, 5]:
if score not in score_ver.columns:
score_ver[score] = 0
score_ver = score_ver[[1, 2, 3, 4, 5]]
score_ver_ratio = score_ver.div(score_ver.sum(axis=1), axis=0) * 100
score_ver_ratio = score_ver_ratio.reset_index()
fig_ver_ratio = px.bar(
score_ver_ratio,
x="version",
y=[1, 2, 3, 4, 5],
title="バージョン別 星評価構成比",
labels={
"value": "構成比(%)",
"version": "アプリバージョン",
"variable": "星評価",
},
barmode="stack",
height=600,
)
fig_ver_ratio.update_layout(
template="plotly_white",
yaxis=dict(range=[0, 100]),
xaxis_tickangle=-45,
)
fig_ver_ratio.show()
fig_ver_ratio.write_html(
"plot_version_ratio.html",
include_plotlyjs="cdn",
full_html=True,
)可視化結果を見るときの注意点
Google Playレビューの可視化では、以下の点に注意が必要です。
- レビューは取得時点のスナップショットであり、過去履歴を完全に再現するものではありません。
- レビュー件数が少ない日は、平均スコアが大きくブレやすくなります。
- アプリバージョンが空のレビューは、バージョン別分析では「不明」として扱うか、除外する必要があります。
- 低評価が増えた理由は、レビュー本文やアップデート履歴とあわせて確認する必要があります。
- 平均スコアだけでなく、星評価の構成比やレビュー件数もセットで見ると解釈しやすくなります。
特に、レビュー件数が少ない期間では、数件のレビューだけで平均スコアが大きく上下します。日次と月次を切り替えながら、細かい変化と長期傾向を分けて見ることが重要です。
次に読む記事
- Google Playレビューのテキスト分析入門|ワードクラウド・共起ネットワーク・TF-IDFをPythonで可視化
- Google Playレビューの感情分析入門|ポジ・ネガ傾向をPythonで月次可視化する方法
- Google Playレビューのトピック抽出入門|LDAとBERTopicで話題を可視化する方法
- Google Playのデータ取得方法まとめ|google-play-scraperでアプリ情報・レビューを取得する
- Google Playレビュー分析まとめ
まとめ
この記事では、Google PlayレビューをPlotlyで可視化し、レビュー件数、平均スコア、星評価構成比、アプリバージョン別の推移を見る方法を紹介しました。
レビュー件数はユーザー反応の量、平均スコアは評価の方向性、星評価構成比は評価の内訳を確認するのに役立ちます。これらを日次・月次で切り替えながら見ることで、アップデートやイベント後の変化を把握しやすくなります。
可視化だけでは理由までは分からないため、次はレビュー本文のテキスト分析や感情分析、トピック抽出と組み合わせて、評価変動の背景を読み解いていきます。