目次
・はじめに
・やりたいこと
・実行環境
・分析してみた
・最後に
・参考
・はじめに
Aidemy Premiumにて「データ分析コース」を3ヶ月受講いたしました。Aidemy Premiumを受講したのは、データ分析、機械学習、Pythonを学びそれを仕事に活かしたと思ったことがきっかけです。
Pythonもデータ分析も初心者なので、至らない点が多々あると思いますが、温かい目で見守って頂ければと思います。
・実行環境
Python 3.7.13
Google Colaboratory
・やりたいこと
普段からアニメが好きなので、Kaggleの「Anime list」 を用いて、高評価となっているアニメの要因を分析し、次にどんな特徴があるアニメが流行るか分析したいと思います。
・分析してみた
1.データ全体を確認する
前提として、各カラムの意味は下記の通りです。( Kaggleページより)
カラム
・name: アニメタイトル
・studio: スタジオ名
・theme: テーマ
・tags: 追加のテーマやジャンルなど
・source: ソース(マンガなど)
・rating: 評価点
・year: 放送が開始された年
・synopsis: アニメの概要
・demographic: 対象性年齢区分(少年やキッズなど)
・status: ステータス(放送終了、放送中など)
・eps: エピソード数
・eps_avg_duration_in_min: 1話あたりの長さ(分)
・rated_by: レビュー数
1-1.まずはデータを読み込みます。
import pandas as pd
df = pd.read_csv("/content/anime-list.csv", index_col=0)
display(df.head())
1-2.shapeを確認します。
print(f'shape : {df.shape}\n')
出力結果
→shape : (3005, 13)
13カラム、3005行のデータ
であることがわかります。
1-3.次に、データの統計量を表示します。
print(f'{df.dtypes} \n')
出力結果
name | objects |
---|---|
studio | object |
theme | object |
tags | object |
source | object |
rating | float64 |
year | float64 |
synopsis | object |
demographic | object |
status | object |
eps | float64 |
eps_avg_duration_in_min | float64 |
rated_by | object |
数値データの統計量
display(df.describe())
index | rating | year | eps | eps_avg_duration_in_min |
---|---|---|---|---|
count | 1812.0 | 2949.0 | 2890.0 | 2950.0 |
mean | 7.043311258278146 | 2007.2641573414717 | 43.062283737024224 | 18.194576271186442 |
std | 0.7760967667136169 | 12.151285471626275 | 75.14915315176842 | 8.01981932089218 |
min | 2.93 | 1963.0 | 2.0 | 0.0 |
25% | 6.49 | 2002.0 | 13.0 | 12.0 |
50% | 7.05 | 2011.0 | 26.0 | 23.0 |
75% | 7.55 | 2016.0 | 51.0 | 24.0 |
max | 9.14 | 2023.0 | 1787.0 | 50.0 |
coutより全カラム欠損データがあることがわかります。
ratingは最大9.14、最小2.93なのでおそらく10点満点の評価だと思います。
数値以外
display(df.describe(exclude='number'))
index | name | studio | theme | tags | source | synopsis | demographic | status | rated_by |
---|---|---|---|---|---|---|---|---|---|
count | 3005 | 3005 | 3005 | 2470 | 2510 | 2315 | 3005 | 2981 | 3005 |
unique | 3005 | 242 | 323 | 358 | 15 | 2309 | 5 | 4 | 995 |
top | Shingeki no Kyojin | Unknown | Kids | Comedy | Manga | It is based on N.Y.SALAD written by Yoshitaka Amano. It depicts lives of vegetable fairies at a kitchen in N. Y.StudioUnknownSourceDemographicKids | Kids | Finished | 0 |
freq | 1 | 1032 | 1002 | 252 | 1181 | 2 | 1376 | 2850 | 277 |
欠損データについても確認します
df.isna().sum()
出力結果
name | count |
---|---|
name | 0 |
studio | 0 |
theme | 0 |
tags | 535 |
source | 495 |
rating | 1193 |
year | 56 |
synopsis | 690 |
demographic | 0 |
status | 24 |
eps | 115 |
eps_avg_duration_in_min | 55 |
rated_by | 0 |
2.カラム確認と前処理
次にカラムの値を確認します。
分析で利用できそうなカラムだけピックアップして記載します。
欠損値などは後々分析しやすいよう前処理も合わせて行います。
2-1.studio(スタジオ名)
データを集計して最も多いものトップ10を表示します
df["studio"].value_counts().head(10)
2-2.theme(テーマ)
データを集計して最も多いものトップ10を表示します
df["theme"].value_counts().head(10)
Kidsが最大となっていることがわかります。
2-3.source(ソース(マンガなど))
データを集計して最も多いものトップ10を表示します
df["source"].value_counts().head(10)
Mangaが最大となっていることがわかります。
アニメオリジナルが多いのは個人的には以外でした。
また、項目にOtherがありました。
本来他の項目もちゃんとみて欠損データをどう補完するか検討したほうが良いかもしれませんが、
今回は、欠損データはすべてOtherにしたいと思います。
df.source.fillna("Other", inplace=True)
df["source"].value_counts().head(10)
2-4.demographic(対象年齢)
unique数も少ないので、ヒストグラフとして表示します。
sns.countplot(x="demographic", data=df)
df["source"].value_counts().head(10)
plt.show()
2-5.year(放送が開始された年)
同じくヒストグラフとして表示します。
import seaborn as sns
sns.histplot(data=df, x="year")
出力結果
2000年あたりから急激に数が増えてきていることがわかります。
2-6.status(ステータス(放送終了、放送中など))
データを集計して最も多いものトップ10を表示します
df["status"].value_counts().head(10)
Finishedは既に放送が終了しているもの、Airingが現在放送中のものであることがわかりますが、
残りのNotとished、欠損データについては状況が不明なので、
もう少し詳細を確認します。
Not
df[df.status == "Not"].head()
出力結果
index | name | studio | theme | tags | source | rating | year | synopsis | demographic | status | eps | eps_avg_duration_in_min | rated_by |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
139 | Chainsaw Man | MAPPA | Gore, Mythology | Action, Adventure | Manga | NaN | 2022.0 | Denji has a simple dream—to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his crushing debts. Using his pet devil Pochita as a weapon, he is ready to do anything for a bit of cash.Unfortunately, he has outlived his usefulness and is murdered by a devil in contract with the yakuza. However, in an unexpected turn of events, Pochita merges with Denji's dead body and grants him the powers of a chainsaw devil. Now able to transform parts of his body into chainsaws, a revived Denji uses his new abilities to quickly and brutally dispatch his enemies. Catching the eye of the official devil hunters who arrive at the scene, he is offered work at the Public Safety Bureau as one of them. Now with the means to face even the toughest of enemies, Denji will stop at nothing to achieve his simple teenage dreams.[Written by MAL Rewrite]StudioMAPPASourceMangaThemesGoreMythologyDemographicShounen | Shounen | Not | NaN | NaN | 386K |
265 | Boku no Hero Academia 6th Season | Unknown | School, Super Power | Action | Manga | NaN | 2022.0 | Sixth season of Boku no Hero Academia.StudioUnknownSourceMangaThemesSchoolSuperPowerDemographicShounen | Shounen | Not | NaN | NaN | 154K |
319 | Bleach: Sennen Kessen-hen | Unknown | Shounen | Action,Adventure,Fantasy | Manga | NaN | 2022.0 | NaN | Shounen | Not | NaN | NaN | 111K |
339 | Dr. Stone 3rd Season | Unknown | Time Travel | Adventure, Comedy, Sci-Fi | Manga | NaN | 2023.0 | Third season of Dr. Stone, airing in 2023.StudioUnknownSourceMangaThemeTime TravelDemographicShounen | Shounen | Not | NaN | NaN | 94K |
タイトルをGoogleで数件調べたのと、上記よりyearが2022、2023となっているため放送日は決まっているがまだ開始していないものが「Not」だと推測できます。
そのため、わかりやすく「comming soon」に変更したいと思います。
df["status"].replace("Not", "comming soon", inplace=True)
次に、ished
df[df.status == "ished"]
※件数が多いので、上位5件のみ表示
出力結果
index | name | studio | theme | tags | source | rating | year | synopsis | demographic | status | eps | eps_avg_duration_in_min | rated_by |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
870 | Shaolin Chuanqi | Unknown | Martial Arts | Action, Adventure, Comedy, Fantasy | Other | NaN | NaN | NaN | Shounen | ished | 26.0 | 22.0 | 111 |
2232 | Xing Mao Lixian Ji Zhi Shu Fa Pian | Unknown | Kids | Adventure | Other | NaN | NaN | Chisese series about the adventures of Star Cat.StudioUnknownSourceDemographicKids | Kids | ished | 26.0 | 12.0 | 198 |
2282 | Wu Lan Qi Qi Ge | Unknown | Historical | NaN | Other | NaN | NaN | NaN | Kids | ished | 26.0 | 22.0 | 171 |
2490 | G Fighters | Unknown | Kids | Action, Sci-Fi | Original | NaN | NaN | NaN | Kids | ished | 26.0 | 23.0 | 47 |
2494 | Baobao Yue Xuetang: Binfen Kuaile Hao | Unknown | Kids | Adventure, Comedy | Original | NaN | NaN | NaN | Kids | ished | 180.0 | 25.0 | 46 |
中国のアニメも多そうな気がし、ratingもyearもNanなので分析では使えなさそうなので、
「ished」のデータは削除してしまいます。
df.drop(df[df["status"] == "ished"].index, inplace=True)
最後に、欠損値
df[df.status.isna()]
※件数が多いので、上位5件のみ表示
出力結果
index | name | studio | theme | tags | source | rating | year | synopsis | demographic | status | eps | eps_avg_duration_in_min | rated_by |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
352 | Tonikaku Kawaii 2nd Season | Unknown | Shounen | Comedy, Romance | Manga | NaN | NaN | Second season of Tonikaku Kawaii.StudioUnknownSourceMangaDemographicShounen | Shounen | NaN | NaN | NaN | 85K |
428 | Fairy Tail: 100 Years Quest | Unknown | Shounen | Action, Adventure, Fantasy | Manga | NaN | NaN | The 100 Years Quest: a mission so challenging and hazardous that it has remained unaccomplished for over a century. While countless mages have attempted to take on this grueling objective, their results ended in either overwhelming defeat or worse. Nonetheless, Natsu Dragneel and his friends—Lucy Heartfilia, Gray Fullbuster, Erza Scarlet, and Wendy Marvell, along with the exceeds Happy and Charlés—ambitiously embark on the quest.A year after the Fairy Tail guild has overcome the diabolical forces of Acnologia and Zeref, Natsu and his team trek into the northern continent of Guiltina, where they seek out the employer of the 100 Years Quest and receive their nearly impossible mission: to seal away the Five Dragon Gods—a group of individuals with such vast power that, if left alone, could cause global devastation. Meanwhile, a spirited new member named Touka is recruited to Fairy Tail. Although her vibrant energy and passionate nature makes her perfect for the guild, there seems to be more to her than meets the eye.Determined to accomplish their seemingly insurmountable mission, Natsu and his friends begin their treacherous search for the Dragon Gods. However, once encountering a new dark guild named Diabolos, along with the newest recruit of Fairy Tail revealing her true colors, Natsu and his team will find that the 100 Years Quest isn't the only challenge they face. [Written by MAL Rewrite]StudioUnknownSourceMangaDemographicShounen | Shounen | NaN | NaN | NaN | 49K |
435 | Jigokuraku | MAPPA | Historical | NaN | Manga | NaN | NaN | Gabimaru the Hollow, a ninja of Iwagakure Village known for being cold and emotionless, was set up by his fellow ninja and is now on death row. Tired of killing and betrayal, he wants to die. However, no method of execution works on him because as much as the seemingly apathetic Gabimaru refuses to admit it, he does have a reason to live. He wants to return to his wife, who was the reason why he softened up and failed to be an effective assassin. Thus, he refuses to die.Asaemon the Decapitator, a famous executioner, sees this and has a proposal for the ninja. He wants Gabimaru to join an expedition to an island south of Japan in search of the elixir of life in exchange for a full pardon by the Shogunate. However, this island isn't a normal island: it's believed to be Paradise.However the island is full of mysteries, and the exploring team—consisting of those marked for death—might not be fully prepared to handle them.[Written by MAL Rewrite]StudioMAPPASourceMangaThemeHistoricalDemographicShounen | Shounen | NaN | NaN | NaN | 47K |
607 | Mato Seihei no Slave | Seven Arcs | Harem | Action, Fantasy, Supernatural | Manga | NaN | NaN | When entrances to a different dimension known as the "Mato" emerge all over Japan, a new resource known as "Peaches" are discovered which give unique abilities only to women. However, dangerous monsters called "Yomotsu Shuuki" also roam throughout the Mato and have been responsible for various disasters ever since. To combat them, the government formed the Anti-demon Corps, an elite group of women who have received power from the Peaches.One day, a high school student named Yuuki Wakura was walking home from school when he suddenly got lost in a Mato entrance. When he calls for help, he is immediately rescued by Kyouka Uzen, the chief of the Seventh Unit of the Anti-demon Corps. Recognizing his potential while also needing him to make her Peach power more effective, she asks that Yuuki join the Anti-demon Corps by becoming her slave, a position he might find more enjoyable than he initially would have thought... (Source: MU, edited)StudioSeven ArcsSourceMangaThemeHaremDemographicShounen | Shounen | NaN | NaN | NaN | 12K |
タイトルをGoogleで数件調べたところ、制作中のアニメで放送日が決まっていないものが「NaN」だと推測できます。
そのため、わかりやすく「no release date」に変更したいと思います。
df["status"].fillna("no release date", inplace=True)
最後にもう一度確認する。
df["status"].value_counts().head(10)
2-7.rated_by(レビュー数)
データを集計して最も多いものトップ10を表示します
df["rated_by"].value_counts().head(10)
1,000=K、1,000,000=Mとアルファベットで表記されているので、利用しやすいようにreplaceで数値に変換します。
df["rated_by"] = df["rated_by"].replace({"K":"*1000", "M":"*1000000"}, regex=True).map(pd.eval).astype(int)
display(df["rated_by"].value_counts())
正しく変換できました。
2-8.eps(エピソード数)
データを集計して最も多いものトップ10を表示します
df["eps"].value_counts().head(10)
epsの欠損データは
df[(df['eps'].isna())]
この内、statusが「Airing,comming soon,no release date」のものが大半で、4件だけstatusが「Finished」のものがあった。
なぜepsがNanなのか不明だが、ratingもNanなので削除する。
df.drop(df[(df['eps'].isna()) & (df.status =="Finished")].index, inplace=True)
2-9.rating(評価点)
最後にratingです。
高評価となっているアニメの要因分析を行う目的なので、statusがFinishedでratingが欠損値、rated_byが0件以外のものは削除します。
df.drop(df[(df['rating'].isna()) & (df.status =="Finished") & (df.rated_by !=0)].index, inplace=True)
ヒストグラフとして表示します。
import seaborn as sns
sns.displot(data=df, x="rating")
2-10.放送終了・放送中に絞る
今回は、高評価となっているアニメの要因分析までしか取り組まないためデータを放送終了・放送中のものだけに絞ります。
今後は今回の分析をもとに公開予定のアニメが流行るかどうか分析できるまで取り組みたいです・・・。
df2 = df[df["status"].isin(["Finished", "Airing"])].copy()
df2.info()
3.高評価となっているアニメの要因分析
まず何をもって高評価とするか決める。
今回はratingの上位5%を高評価として定義する。
import numpy as np
np.percentile(df2["rating"].dropna(), 95)
出力結果
8.368999999999996
上位5%を区別するため、列を追加する。
df2['TopFlg'] = 0
df2.loc[df2[df2["rating"] >=8.368999999999996].index, 'TopFlg'] = 1
追加した列と他のカラムの相関を確認します。
import seaborn as sns
sns.heatmap(df2.corr(), annot=True)
1に近いほど相関があるので、このなかでいうとrateed_byくらいが相関がありそうですが、
他はあまり相関がなさそうです。以降で深掘りしていきます。
3-1.studioから見ていきます
グラフにしてみたのですが、ユニーク数が多く見れないので、
データを確認します。
df2[df2["TopFlg"] == 1]["studio"].value_counts().head()
出力結果
Madhouseが高評価のアニメを一番出しています。
はじめの一歩や、NANAなどが入ってました。
単純に出しているアニメが多いだけかもしれないので確率を求めてみます。
df2["studio"].value_counts()
df3=pd.concat([df2[df2["TopFlg"] == 1]["studio"].value_counts(),df2["studio"].value_counts()],axis=1,keys=["topflg1","sum"])
df3["kaku"] = df3['topflg1']/df3["sum"]*100
display(df3[df3['topflg1'].notna()].sort_values('kaku',ascending=False).head(7))
Shuka、Egg Firmは2件中2件高評価となっています。
Wit Studioは10件中5件となっています。
Madhouseより、上記スタジオのほうが高評価を出す確率は高そうです。
3-2.次はthemeです。
themeはカンマ区切りで複数1列に登録されているので、
分割して件数を確認します。
themes = []
for theme in df2[df2["TopFlg"] == 1]["theme"].tolist():
themes.extend(theme.split(", "))
pd.Series(themes).value_counts().head(10)
出力結果
Historical(歴史)とSchool(学校)が多く含まれているものが高評価が多いです。
鬼滅の刃・キングダム、呪術廻戦・スラムダンクなどが入っていました。
3-3.次はtagsです。
theme同様カンマ区切りで複数1列に登録されているので、
分割して件数を確認します。
# tagsがfloatになっていたのでstrに変換する
df2 = df2.astype(
{
'tags' : str
}
)
themes = []
for theme in df2[df2["TopFlg"] == 1]["tags"].tolist():
themes.extend(theme.split(", "))
pd.Series(themes).value_counts().head(10)
出力結果
アクションとドラマが多く含まれているものが高評価が多いです。
進撃の巨人・鋼の錬金術師、ジョジョの奇妙な冒険・ちはやふるなどが入ってました。
3-4.次はsourceです。
import matplotlib.pyplot as plt
sns.countplot(x= 'source',hue='TopFlg',data=df2)
plt.legend(title='TopFlg', loc='upper right')
plt.xticks(rotation=90)
plt.tight_layout()
plt.show()
出力結果
漫画原作のものがダントツで1位でした。
評価関わらず、総数も漫画がダントツでした。
3-5.次はyearです。
グラフにするとx軸が見にくいので8つの区間に分類してからグラフ化しました。
df2['yearBunrui'] = pd.qcut(df2['year'],8)
import matplotlib.pyplot as plt
sns.countplot(x= 'yearBunrui',hue='TopFlg',data=df2)
plt.legend(title='TopFlg', loc='upper right')
plt.xticks(rotation=90)
plt.tight_layout()
plt.show()
1990年台と古いものは高評価のものがないですが、以降の年によって大きな変化はなかったので、放送開始年は特に高評価の要因とは関係ないと判断しました。
3-6.次はdemographicです。
import matplotlib.pyplot as plt
sns.countplot(x= 'demographic',hue='TopFlg',data=df2)
plt.legend(title='TopFlg', loc='upper right')
plt.xticks(rotation=90)
plt.tight_layout()
plt.show()
少年と青年で大半を占めています。
Kidsは総数は多いのですが高評価は0件でした。
ポケモンやデジモンなど高評価が付きそうなものがあったのですが7点台が大半でした。
対象年齢が低いと良い評価を得にくいと判断しました。
3-7.次はepsです。
グラフにするとx軸が見にくいので6つの区間に分類してからグラフ化しました。
df2['epsBunrui'] = pd.qcut(df2['eps'],6)
import matplotlib.pyplot as plt
sns.countplot(x= 'epsBunrui',hue='TopFlg',data=df2)
plt.legend(title='TopFlg', loc='upper right')
plt.xticks(rotation=90)
plt.tight_layout()
plt.show()
エピソード数と高評価は、前段の結果と同様やはり相関がないようでした。
エピソード数が多い=長く続いているので高評価かと分析前は思っていたのですが関係なさそうです。
実際のデータを見ると、1つのアニメでもシーズン1、2と別れているためこのような結果になっていました。
3-7.次はeps_avg_duration_in_minです。
import matplotlib.pyplot as plt
sns.countplot(x= 'eps_avg_duration_in_min',hue='TopFlg',data=df2)
plt.legend(title='TopFlg', loc='upper right')
plt.xticks(rotation=90)
plt.tight_layout()
plt.show()
display(df2[df2["TopFlg"] == 1]["eps_avg_duration_in_min"].value_counts())
22-26分に高評価が集まっていました。
大体のアニメがこの範囲に集まっているので当然の結果かなと思いました。
youtubeやTikTokなどショート動画が流行っているので今後は短いものが高評価を得るなどもあるかもしれません。
3-8.最後にrated_byです。
これもグラフにするとx軸が見にくいので8つの区間に分類してからグラフ化しました。
df2['rated_byBunrui'] = pd.qcut(df2['rated_by'],8)
import matplotlib.pyplot as plt
sns.countplot(x= 'rated_byBunrui',hue='TopFlg',data=df2)
plt.legend(title='TopFlg', loc='upper right')
plt.xticks(rotation=90)
plt.tight_layout()
plt.show()
評価数が多くなると高評価を得やすい結果となりました。
やはり相関が強いようです。
3-8.まとめ
上記結果をまとめると、
・スタジオは、Shuka、Egg Firm、Wit Studioあたりが良い
・テーマとしては、歴史、学園ものが良い
・ジャンルは、アクション系、ドラマ系が良い
・ソースは、マンガ原作!!
・対象年齢としては、少年・青年が良い
・1話あたりの長さは、22-26分程度
・レビュー数が多い=高評価。
すべて該当しないが、放送予定のもので上記に該当するものはアンダーニンジャ、チェンソーマンなどがヒットしました。
(分析しなくてもわかりそうなタイトルですが・・)
最後に
今回はKaggleのコードなども参考にしながら少しデータを分析してみました。
実際に分析してみることで知識が定着したが、もっと頑張らないとと反省しました…。
今後は仕事の中でも分析していこうと思うので、今回の経験を活かし勉強に励みたいと思います!
参考
□データセット https://www.kaggle.com/datasets/pmanthan/anime-list-2022
□参考サイト
https://myfrankblog.com/data_analysis_with_anime_review_data_part1/
https://myfrankblog.com/finding_best_animation_from_data/
https://myfrankblog.com/analyzing_good_review_anime/
(すみません、めちゃくちゃ参考にさせて頂きました。ほぼ類似してしまい申し訳ございません。)