この記事では、Google Playの検索結果とアプリ詳細情報を使って、ゲーム会社ごとの得意ジャンルやタイトル分布をPythonで可視化する方法を解説します。
Google Playには多くのゲームアプリが公開されていますが、「どの会社がどのジャンルに多くタイトルを出しているのか」「インストール規模の大きいタイトルを持つ会社はどこか」を手作業で把握するのは大変です。
そこで本記事では、google-play-scraper の search() と app() を使い、検索キーワードからアプリ候補を集め、開発会社・ジャンル・評価・インストール規模を集計して可視化します。
この記事でできること
- Google Playの検索結果からアプリ候補を取得する
- アプリIDを使って詳細情報を取得する
- 検索結果の重複アプリを除外する
- 運営会社別のタイトル数を集計する
- インストール規模別にタイトル分布を可視化する
- ジャンル×運営会社の分布をヒートマップで確認する
- 検索結果ベースの分析で注意すべき点を理解する
想定読者
- Google Playのゲームアプリをジャンル別に比較したい方
- 特定ジャンルに強いゲーム会社をデータで見たい方
- アプリ市場の簡易調査をPythonで行いたい方
- Google Playレビュー分析の応用例を知りたい方
- 検索結果からアプリ一覧を作り、可視化したい方
分析上の注意点
本記事の分析は、Google Playの検索結果をもとにした簡易的な可視化です。Google Play上のすべてのゲームアプリや、各会社の全タイトルを網羅するものではありません。
- 検索キーワードにヒットした範囲のアプリのみが対象です。
- 検索結果は時期、地域、言語、検索語によって変わる可能性があります。
- 同じ会社でも、Google Play上の開発者名が表記ゆれする場合があります。
- インストール数は正確な実数ではなく、Google Play上の表示区分を使います。
- 検索結果ベースのため、「強い会社」を厳密にランキングするものではありません。
そのため、本記事の結果は「市場全体の完全なランキング」ではなく、検索条件に基づく傾向把握として扱うのが適切です。
事前準備
Google Playのデータ取得には、google-play-scraper を使います。基本的な使い方は以下の記事でも解説しています。
Google Playのデータ取得方法まとめ|google-play-scraperでアプリ情報・レビューを取得する
今回使う主な関数は以下です。
| 関数 | 用途 |
|---|---|
search() | 検索キーワードからアプリ候補を取得する |
app() | アプリIDを指定して詳細情報を取得する |
使用ライブラリ
データ取得には google-play-scraper、集計には pandas、可視化には plotly を使います。進捗表示には tqdm を使います。
pip install -U google-play-scraper pandas plotly tqdm検索条件を設定する
まず、検索に使うジャンル系キーワードを用意します。検索語を複数指定することで、1つのキーワードでは拾えないアプリ候補を広げます。
LANG = "ja"
COUNTRY = "jp"
queries = [
"RPG",
"ロールプレイング",
"シミュレーション",
"経営 シミュレーション",
"パズル",
"アクション",
"アドベンチャー",
"カジュアル",
"シューティング",
"カードゲーム",
"音楽 ゲーム",
]
n_hits_per_query = 200
pause_sec = 1.0n_hits_per_query は、1つの検索語ごとに取得する件数の上限です。検索結果はGoogle Play側の仕様や検索語によって変わるため、必ず指定件数分が取得できるとは限りません。
検索結果を取得する
search() を使って、検索キーワードごとにアプリ候補を取得します。どの検索語でヒットしたか分かるように、query も一緒に保存します。
from google_play_scraper import search
import pandas as pd
from tqdm import tqdm
def fetch_search_results(
queries: list[str],
lang: str = "ja",
country: str = "jp",
n_hits: int = 200,
) -> pd.DataFrame:
rows = []
for query in tqdm(queries, desc="Searching"):
try:
results = search(
query,
lang=lang,
country=country,
n_hits=n_hits,
)
for item in results:
rows.append({
"search_query": query,
**item,
})
except Exception as e:
print("検索失敗:", query, e)
return pd.DataFrame(rows)
df_search = fetch_search_results(
queries=queries,
lang=LANG,
country=COUNTRY,
n_hits=n_hits_per_query,
)
print("search rows:", len(df_search))
print(df_search.head())検索結果には同じアプリが複数のキーワードで出てくることがあります。そのため、後続処理では appId を使って重複を除外します。
アプリIDをユニーク化する
検索結果から、重複しないアプリIDの一覧を作成します。
if "appId" not in df_search.columns:
raise ValueError("検索結果に appId 列がありません。")
unique_app_ids = (
df_search["appId"]
.dropna()
.drop_duplicates()
.sort_values()
.tolist()
)
print("ユニークアプリ数:", len(unique_app_ids))このユニークアプリIDに対して、app() で詳細情報を取得していきます。
アプリ詳細を取得する
search() の結果は軽量な情報に限られるため、評価数、インストール数、ジャンル、開発会社などを詳しく使いたい場合は、app() で詳細情報を取得します。
import time
from google_play_scraper import app
def fetch_app_details(
app_ids: list[str],
lang: str = "ja",
country: str = "jp",
pause_sec: float = 1.0,
) -> pd.DataFrame:
rows = []
for app_id in tqdm(app_ids, desc="Fetching details"):
try:
detail = app(
app_id,
lang=lang,
country=country,
)
rows.append(detail)
time.sleep(pause_sec)
except Exception as e:
print("詳細取得失敗:", app_id, e)
return pd.DataFrame(rows)
df_app = fetch_app_details(
app_ids=unique_app_ids,
lang=LANG,
country=COUNTRY,
pause_sec=pause_sec,
)
print("detail rows:", len(df_app))
print(df_app.head())複数アプリの詳細取得ではリクエスト数が増えるため、pause_sec で間隔を空けています。短時間に大量アクセスするような使い方は避けてください。
必要な列を整える
分析に使う列だけを取り出し、インストール数の表示を区分化します。
def parse_installs_to_band(value: str) -> str:
if not isinstance(value, str) or value.strip() == "":
return "unknown"
text = value.replace(",", "").replace("+", "").strip()
try:
installs = int(text)
except ValueError:
return "unknown"
if installs < 10_000:
return "0-10K"
if installs < 100_000:
return "10K-100K"
if installs < 1_000_000:
return "100K-1M"
if installs < 10_000_000:
return "1M-10M"
return "10M+"Google Playのインストール数は、厳密な実数ではなく「10,000+」「1,000,000+」のような表示です。ここでは比較しやすいように、インストール帯として扱います。
cols = [
"appId",
"title",
"score",
"ratings",
"reviews",
"installs",
"minInstalls",
"genre",
"genreId",
"developer",
"developerId",
"free",
"price",
"currency",
]
df_app = df_app.reindex(columns=cols)
df_app["install_band"] = df_app["installs"].map(parse_installs_to_band)
first_query = (
df_search.groupby("appId")["search_query"]
.first()
.rename("first_search_query")
)
df_app = df_app.merge(
first_query,
how="left",
left_on="appId",
right_index=True,
)
df_app.to_csv(
"googleplay_game_app_details.csv",
index=False,
encoding="utf-8-sig",
)
print(df_app.head())このCSVを保存しておくと、後から条件を変えて再集計したり、別の可視化に使ったりできます。
運営会社別にタイトル数を集計する
まず、運営会社ごとにタイトル数、平均スコア、レビュー数などを集計します。
developer_summary = (
df_app.dropna(subset=["developer"])
.groupby("developer")
.agg(
titles=("appId", "nunique"),
avg_score=("score", "mean"),
median_score=("score", "median"),
total_ratings=("ratings", "sum"),
total_reviews=("reviews", "sum"),
)
.reset_index()
.sort_values("titles", ascending=False)
)
developer_summary.to_csv(
"developer_summary.csv",
index=False,
encoding="utf-8-sig",
)
print(developer_summary.head(20))タイトル数が多い会社は、対象検索キーワードに多くヒットしている会社です。ただし、検索語の設計に影響されるため、そのまま市場シェアとは解釈しないように注意します。
運営会社別タイトル数を可視化する
タイトル数の多い運営会社を棒グラフで表示します。
import plotly.express as px
top_developers = (
developer_summary
.head(20)
.sort_values("titles")
)
fig_titles = px.bar(
top_developers,
x="titles",
y="developer",
orientation="h",
title="運営会社別タイトル数(上位20)",
text="titles",
)
fig_titles.update_traces(textposition="outside")
fig_titles.update_layout(
template="plotly_white",
height=900,
xaxis_title="タイトル数",
yaxis_title="運営会社",
)
fig_titles.show()
fig_titles.write_html(
"dev_top_titles.html",
include_plotlyjs="cdn",
full_html=True,
)インストール帯ごとの構成比を集計する
次に、運営会社ごとにインストール帯の構成比を確認します。タイトル数が多くても、小規模タイトルが中心なのか、大規模タイトルを多く持つのかで見方が変わります。
install_pivot = (
df_app.pivot_table(
index="developer",
columns="install_band",
values="appId",
aggfunc="nunique",
fill_value=0,
)
.reset_index()
)
band_order = [
"0-10K",
"10K-100K",
"100K-1M",
"1M-10M",
"10M+",
"unknown",
]
for band in band_order:
if band not in install_pivot.columns:
install_pivot[band] = 0
install_pivot["total_titles"] = install_pivot[band_order].sum(axis=1)
for band in band_order:
install_pivot[f"{band}_ratio"] = (
install_pivot[band] / install_pivot["total_titles"]
).fillna(0)
print(install_pivot.head())10M+タイトル比率を可視化する
一定数以上のタイトルを持つ会社に絞り、10M+インストール帯のタイトル比率を可視化します。
summary = developer_summary.merge(
install_pivot[["developer", "total_titles", "10M+_ratio"]],
on="developer",
how="left",
)
min_titles = 3
top_10m_ratio = (
summary[summary["titles"] >= min_titles]
.sort_values("10M+_ratio", ascending=False)
.head(20)
.sort_values("10M+_ratio")
.copy()
)
top_10m_ratio["ratio_label"] = top_10m_ratio["10M+_ratio"].map(
lambda value: f"{value:.0%}"
)
fig_10m = px.bar(
top_10m_ratio,
x="10M+_ratio",
y="developer",
orientation="h",
title=f"運営会社別 10M+タイトル比率(タイトル数≥{min_titles})",
text="ratio_label",
)
fig_10m.update_traces(textposition="outside")
fig_10m.update_layout(
template="plotly_white",
height=900,
xaxis_title="10M+タイトル比率",
yaxis_title="運営会社",
xaxis_tickformat=".0%",
)
fig_10m.show()
fig_10m.write_html(
"dev_ratio_10m.html",
include_plotlyjs="cdn",
full_html=True,
)この指標は「大規模インストール帯のタイトルを持つ割合」を見るものです。ただし、検索結果に含まれたタイトルだけが対象なので、会社全体の実績を完全に表すものではありません。
インストール帯の構成比を可視化する
タイトル数上位の会社について、インストール帯の構成比を100%積み上げ棒グラフで確認します。
top10_developers = developer_summary.head(10)["developer"]
stack_df = (
install_pivot[install_pivot["developer"].isin(top10_developers)]
.copy()
.sort_values("total_titles", ascending=False)
)
ratio_cols = [f"{band}_ratio" for band in band_order if band != "unknown"]
fig_install_mix = px.bar(
stack_df,
x="developer",
y=ratio_cols,
barmode="stack",
title="運営会社別 インストール帯構成比(タイトル数上位10社)",
labels={
"value": "構成比",
"variable": "インストール帯",
"developer": "運営会社",
},
)
fig_install_mix.for_each_trace(
lambda trace: trace.update(
name=trace.name.replace("_ratio", "")
)
)
fig_install_mix.update_layout(
template="plotly_white",
height=900,
yaxis_tickformat=".0%",
xaxis_tickangle=-30,
)
fig_install_mix.show()
fig_install_mix.write_html(
"dev_install_mix.html",
include_plotlyjs="cdn",
full_html=True,
)ジャンル×運営会社の分布をヒートマップで見る
最後に、ジャンルと運営会社の組み合わせをヒートマップで確認します。どの会社がどのジャンルに多くタイトルを持っているかを俯瞰できます。
developer_genre = (
df_app.pivot_table(
index="developer",
columns="genre",
values="appId",
aggfunc="nunique",
fill_value=0,
)
.reset_index()
)
genre_cols = [
col
for col in developer_genre.columns
if col != "developer"
]
heatmap_df = (
developer_genre[
developer_genre["developer"].isin(top10_developers)
]
.set_index("developer")[genre_cols]
)
fig_heatmap = px.imshow(
heatmap_df,
aspect="auto",
title="ジャンル×運営会社:タイトル数ヒートマップ",
)
fig_heatmap.update_layout(
template="plotly_white",
height=900,
xaxis_title="ジャンル",
yaxis_title="運営会社",
)
fig_heatmap.show()
fig_heatmap.write_html(
"dev_genre_heatmap.html",
include_plotlyjs="cdn",
full_html=True,
)このヒートマップを見ることで、特定会社がRPG寄りなのか、パズルやカジュアルゲーム寄りなのか、といった傾向を確認しやすくなります。
分析結果を見るときの注意点
この分析は、Google Play検索結果をもとにした簡易分析です。結果を解釈するときは、以下の点に注意してください。
- 検索キーワードにヒットしなかったアプリは対象外です。
- 検索結果の並びや件数は、時期や条件によって変わる可能性があります。
- Google Play上のジャンル分類は、アプリの実態と完全には一致しない場合があります。
- 開発会社名は表記ゆれや配信会社名の違いがあるため、必要に応じて名寄せが必要です。
- インストール数は表示区分であり、正確な実数ではありません。
- タイトル数やインストール帯だけで、会社の実力や売上を断定しないようにします。
より正確に比較したい場合は、検索キーワードを増やす、対象ジャンルを絞る、会社名の名寄せを行う、取得日を記録するなどの工夫が必要です。
この分析の活用例
Google Play検索結果を使った会社・ジャンル分析は、以下のような用途に活用できます。
- 特定ジャンルにタイトルを多く出している会社を探す
- 競合アプリの候補を広く集める
- ジャンル別のアプリ分布をざっくり把握する
- レビュー分析対象のアプリを選定する
- 市場調査の前段階として候補リストを作成する
たとえば、RPG系のレビュー分析を行う前に、RPG関連キーワードで検索結果を集めることで、分析対象候補を広く洗い出せます。
次に読む記事
- Google Playのデータ取得方法まとめ|google-play-scraperでアプリ情報・レビューを取得する
- Google Playレビュー可視化入門|日次・月次の評価推移をPlotlyで分析する方法
- Google Playレビューのテキスト分析入門|ワードクラウド・共起ネットワーク・TF-IDFをPythonで可視化
- Google Playレビューの感情分析入門|ポジ・ネガ傾向をPythonで月次可視化する方法
- Google Playレビューのトピック抽出入門|LDAとBERTopicで話題を可視化する方法
- Google Playレビュー分析まとめ
まとめ
この記事では、Google Playの検索結果とアプリ詳細情報を使って、ゲーム会社ごとのタイトル数、インストール帯、ジャンル分布を可視化する方法を紹介しました。
search() でアプリ候補を集め、app() で詳細情報を補完することで、会社別・ジャンル別の傾向を簡易的に確認できます。
ただし、検索結果ベースの分析は対象範囲に偏りがあります。結果は「検索条件に基づく傾向」として扱い、必要に応じて検索語の追加、名寄せ、取得日の記録、レビュー分析との組み合わせを行うのがおすすめです。