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

# tldr

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

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

## 分析対象データ：vndbとは

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

データはzst形式で保存されているので、以下のコマンドで解凍します。
zstの解凍には[zstd](https://github.com/facebook/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でした。
現実の数値は少し古いですが、論文：[若年成人女子の人体計測データからみた体格・体型特性](https://www.jstage.jst.go.jp/article/jje1965/33/2/33_2_97/_pdf)を参考にします。（以下別府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
)
```

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

![weight.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173499/9bc59817-f88b-38dd-8fea-4aafc7e642e7.png)



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

![height.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173499/02f4f37b-12e3-7232-286e-d4684c4231c7.png)

身長の分布は、正規分布にはならず、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)
```

にすると以下のようになります。
![bust_height.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173499/b0633a21-9efb-b613-eae2-f17988eafd17.png)

これは不思議な図で、ある程度までは胸囲と身長に相関がありますが、ある程度身長が高くなると、突然胸囲だけが増えます。「身長は高すぎると困るが、胸囲は増えても良い」という需要があることがうかがえます。ちなみに、この図だと__相関係数は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を使います。

![haircolor_cupsize.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173499/efc3f874-b6a9-7821-e0f4-121c02f0194f.png)

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|

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

__性格__と__髪の色__を図にまとめます。
![personality_haircolor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173499/5ad3c36a-e605-e4be-025c-3fc96f9b8cda.png)


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

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

![personality_hairstyle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173499/b4a20f1c-057b-fcbb-e38e-bb37a25c0b84.png)

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

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