ツンデレの52%はツインテールで、28%は金髪である。


tldr

こんばんは。midzです。
いわゆる美少女ゲーム/ノベルゲーム/ビジュアルノベルと呼ばれるキャラクターのデータベースにvndbがあります。この記事は、そのキャラクターデータの統計をpythonで分析した結果をまとめたものです。

目的

目的1.分析によって、ユーザーのバイアスを明らかにする。
目的2.統計を出すことによって、創作をする際の参考にできるようにする。

分析対象データ:vndbとは

vndbは、visual novel databaseの略で、海外のビジュアルノベルのデータベースです。データベースとしてはかなり充実していて、各キャラクターの誕生日、体重、スリーサイズ、性格などがデータ化されています。また、データベースもダンプされていて、tsvの形式でダウンロードすることができます。

データはzst形式で保存されているので、以下のコマンドで解凍します。
zstの解凍にはzstdが必要です。

zstd --decompress vndb-db-2021-01-11.tar.zst
tar xvfz vndb-db-2021-01-11.tar 

解凍すると、色んなファイルが出てきますが、基本的にはchars.headerやcharsのように、tsvファイルのカラム名とデータに分かれてファイルが存在します。拡張子は書かれていませんが、tsv(tab separated value)形式です。

headerとデータファイル(<filename>.headerと<filename>)をつなげるとtsvファイルとしてpandasで扱えるようになります。
キャラクターの分析に使えそうなのはchars, traits, traits_parents, chars_traitsです。

chars:名前身長性別誕生日スリーサイズなどのキャラクターの情報が書かれています。
traits:髪型や性格などの付加情報が書かれています。
chars_trait:traitのidとキャラクターのidが紐付けられた情報。
traits_parents:trait間の親子関係(髪traitは髪の長さtraitの親traitに該当する等)を記してある。

欠損しているデータもありますが、約95000人のキャラクターのデータがあります。今回は女性キャラクターに限定して分析をします。
tsvファイルは以下のようにコマンドで読み込めます。

import pandas
chara_df = pandas.read_csv("chars",sep="\t")

見やすいように身長200cm以上などの外れ値は除去します。

身長/体重

身長と体重のデータがあるキャラクター数は5988でした。
身長の平均値は157.82cm。体重は47.12でした。
現実の数値は少し古いですが、論文:若年成人女子の人体計測データからみた体格・体型特性を参考にします。(以下別府97と呼称。)
これによると、18歳〜22歳の日本人女性の平均身長は、158.46cm、体重は51.35でした。身長はほとんど一致していますが、体重は低めでした。BMIで言うと、実際の平均は20.4ですが、vndbの統計では18.9です。一般的にはBMI18.5以下であれば痩せなので、それよりギリギリ上に設定されている感じです。
まとめるとこうです。

身長 体重 BMI
別府97 158.46 51.35 20.4
vndb 157.92 47.12 18.9

体重(weight)の分布(ヒストグラム)を計算します。
グラフ出力にはseabornのdistplotを使います。

import seaborn as sns
sns.distplot(
    chara_df['s_bust'], bins=20, color='#123456',
    kde=False,
    rug=False
)

結果は以下のようになりました。

正規分布に近い分布になっているのではないでしょうか?
身長(height)の分布は以下です。

身長の分布は、正規分布にはならず、150cm前半、150cm代後半、160cm中盤、に3つの山があるように見えます。これは、低身長、中身長、高身長好きのように性癖がユーザー毎に異なるので3つに分散されていることの表れだと思います。

胸囲/腹囲/臀囲

別府97論文による、若年女子の平均胸囲/腹囲/臀囲とvndb上のデータを以下に比較します。

胸囲 腹囲 臀囲
別府97 83.45 62.80 90.57
vndb 84.17 56.54 83.17

胸囲はほぼ同じですが、腹囲、臀囲はかなり少なめになっていることがわかります。

身長(height)と胸囲(s_bust)の相関を散布図を出力します。
出力にはseabornのjointplotを使います。

sns.jointplot('height','s_bust', data=chara_df)

にすると以下のようになります。

これは不思議な図で、ある程度までは胸囲と身長に相関がありますが、ある程度身長が高くなると、突然胸囲だけが増えます。「身長は高すぎると困るが、胸囲は増えても良い」という需要があることがうかがえます。ちなみに、この図だと相関係数は0.610で、身長と胸囲に高い相関があります。
ところが別府97によると、胸囲と身長の相関係数は0.194で、現実では相関が低いようです。需要に応じてキャラクターが作られると仮定すると、低身長女子は貧乳であって欲しいが、高身長女子は巨乳であって欲しいという願望があることがうかがえます。

 髪型と髪の色

髪型は色々あるのですが、今回は数の多いロング(Long)、ショート(Short)、ツインテール(TwinTail)、ポニーテール(PonyTail)に絞って分析します。ちなみに、vndb上のデータだとTwinTailやPonyTailはLongやShortとMECEではない、つまりLongかつTwinTailの属性を持つキャラクターがいますが、今回の分析では、重複していた場合はTwinTailやPonyTailを優先します。また、肩までの長さ(Shoulder-length)という髪型もありましたが、パット見Shortと変わらなかったので同一視しました。

この辺は結構面倒くさい処理をしたので詳細は省きますが、おおまかには、髪型や後述の髪の色、性格の情報はtraitsやchars_traitsに分かれて格納されているので、それをpandas.mergeで結合するという処理をすると分析できます。

pandas.merge(chara_df,chara_traits_df,on="char_id")

統計上の数値は以下です。

データ数 身長 胸囲
ロング 1,568 159.6 87.1
ショート 2,321 157.6 84.0
ツインテール 1,532 153.4 81.0
ポニーテール 1,112 160.4 86.8

身長はポニーテール>ロング>ショート>ツインテールの順になっています。
確かにツインテールが高身長という印象は無いので、イメージとも合っています。

平均値はpandasのgroupbyとmeanを組み合わせると楽に計算できます。
name_yのところは集計したい属性のカラム(この場合は髪型)を入れるとOKです。

chara_df.groupby("name_y").mean()

次に髪の色の分析です。データ数が200以上ある髪の色を分析対象とします。

髪の色 データ数 身長 胸囲
Red 557 159.7 85.9
Black 1112 159.4 85.8
Violet 978 159.2 86.0
Blue 869 158.5 84.8
Grey 218 158.1 83.4
Brown 1,885 158.0 85.4
Green 359 157.8 84.5
Blond 1,398 157.6 85.1
Orange 463 156.4 83.6
White 414 155.8 82.4
Pink 750 155.3 83.7

身長順に並べています。身長や胸が大きいのは赤髪、黒髪、紫髪だという結果になりました。
最も貧乳は白髪で、ピンク髪が最も低身長です。

カップサイズを割合でまとめた図は以下になります。
各髪型で正規化しているので、各髪型のA~Gの割合を足すと1になります。
ここではpandasのcross_tabとseabornのheatmapを使います。

Aカップの割合が多い順でいうと白>ピンク>灰>金髪になります。
髪の色が薄い方が貧乳が多いという傾向にあるようです。
(とはいえ、灰髪金髪はFカップの比率も高いですが)
こういうイメージは無かったので新たな知見が得られたと言えそうです。

性格

次に性格を調査します。

性格 データ数 身長 胸囲
Relaxed(おっとり) 255 159.9 87.2
Tomboy(ボーイッシュ) 202 159.8 84.4
Serious(真面目) 390 159.6 85.8
Arrogant(傲慢) 226 159.2 85.2
Refined(洗練された) 508 159.0 86.2
Smart(賢い) 392 158.2 84.9
Kind(親切) 1247 158.1 86.0
Outgoing(社交的) 231 157.3 84.5
Airhead(アホの子) 248 157.2 85.0
Hardworker(努力家) 459 157.1 83.7
Stubborn(頑固) 230 157.0 83.1
Mischievous(お茶目) 309 157.0 83.2
Honest(正直) 207 156.9 83.6
Tsundere(ツンデレ) 240 156.4 83.4
Reserved(無口) 274 156.3 82.7
Deredere(デレデレ) 426 156.2 85.1
Stoic(ストイック) 274 156.0 81.0
Clumsy(ドジっ子) 316 155.4 83.8
Energetic(元気) 604 154.7 81.6
Naive(純粋) 287 154.6 82.6
Timid(臆病) 229 154.2 82.9
Brocon(ブラコン) 232 153.9 81.7

おっとり、ボーイッシュ、真面目、傲慢系が高身長となりました。
ドジっ子、元気系、純粋、臆病系が低身長です。
この辺はイメージと合っているのでは無いでしょうか。

性格髪の色を図にまとめます。

さきほどと同じように行毎に正規化しています。(横に数字を足していけば1になります)
図を見ると、傲慢キャラで一番多いのは36%の金髪ツンデレキャラで一番多いのも28%の金髪です。
ツンデレは金髪が多いというステレオタイプに合致する結果となりました。

次に、性格髪型の図をまとめます。

なんとツンデレの52%がツインテールという結果になりました。圧倒的多数です。

まとめ

髪型、髪の色、性格、身長、胸囲などの観点からvndb(美少女ゲーム)のキャラの統計をまとめました。
キャラ作りなどの参考にしてください。
他にも面白い知見が得られたら更新します。
コードは(多分)後日githubにアップロードします。