Pythonでグラフを描く⑦violinplotの作成

今回は箱ひげ図の一種であるviolinplotの作成に挑戦した。最近読んだ論文では、violinplotを使って時系列のデータを示していた。violinpotを用いたこの使い方は初めてみた。今回は、論文で使用されていたようなviolinplotを作成してみた。

ちなみにviolinploを使っていた論文は↓に示した。

Eckardt, N., Braun, C., & Kibele, A. (2020). Instability Resistance Training improves Working Memory, Processing Speed and Response Inhibition in Healthy Older Adults: A Double-Blinded Randomised Controlled Trial. Scientific Reports, 10(1), 1-12.
https://rdcu.be/b2Xa5

↑の論文では10週間の筋トレの前(pre)と後(post)に認知機能を評価するテストを行い、習慣的な筋トレが脳機能に与える影響を調べている。ちなみに、ジャーナルの評価の一つとなるインパクトファクターを調べてみると、Scientific Reportsのインパクトファクターは、 4.011(2-year impact factor)みたい。おそらく、いい論文。もっといいと思うのが、自分の論文を引用している点。きっと、いい論文。まあ、そんなことはどうでもいいので、violinplotの作成する。

まずは、いつものコードをを打ち込む。

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')#グラフの背景を白くする
%matplotlib inline

「Pythonでグラフを描く⑥箱ひげ図の作成」で使用した時と同じデータを今回も使う。データは↓からダウンロードできる。

まずは、読み込み。

df=pd.read_csv('sample2.csv')

基本コードは「Pythonでグラフを描く⑥箱ひげ図」で作成したグラフと同じ。boxplotをviolinplotに変えるだけ。プログラミングでグラフを書くといい点は、一度コードを作成できればあとはコピペでグラフが作れちゃう点。EXCELなどでグラフをつくるのもいいが、マウス操作の場合、新しいグラフを作ろうと思うと毎回ゼロからグラフを作らないといけない。プログラミングに慣れてきたら、こんな非効率なことはないと感じるようになる。

plt.figure(figsize=(20,10))#グラフの大きさ設定
sns.set_style('ticks')#grid腺を消す
sns.violinplot(x="timing", y="Score", data=df, palette="Greys")
plt.tick_params(labelsize = 30)#軸ラベルの大きさ
plt.title("Mean", size=50)#グラフのタイトル
plt.ylabel("Score", size=50)#y軸ラベル
plt.xlabel("")#x軸ラベルの消去

画像1

violinplot完成。ただ、今回はカラフルにしてみる。

plt.figure(figsize=(20,10))#グラフの大きさ設定
sns.set_style('ticks')#grid腺を消す
sns.violinplot(x="timing", y="Score", data=df, palette="pastel")
plt.tick_params(labelsize = 30)#軸ラベルの大きさ
plt.title("Mean", size=50)#グラフのタイトル
plt.ylabel("Score", size=50)#y軸ラベル
plt.xlabel("")#x軸ラベルの消去

画像6

色の変更はviolinplot()のなかのpaletteで調整する。paletteの種類に関しては↓を参照した。

Choosing color palettes
https://seaborn.pydata.org/tutorial/color_palettes.html

ここから、冒頭で紹介した論文のようなviolinplotの作成に挑む。

まずは、データセットを変更する。男性と女性の性別のデータを加える。男性と女性のそれぞれにおいて、pre、post1、post2のviolinplotを描くことにする。

性別を適当に振り分けるために、まずは0から100の乱数を1500行発生させる。この乱数をdf_2としてデータフレームに格納する。

from numpy.random import *
df_2=DataFrame(randint(0,100,(1500,1)))

次に、sample2.csvを格納したdfと結合する。結合したデータフレームをdf_allとしておく。

df_all=pd.concat([df,df_2],axis=1)

中身を確認しておく。

df_all.head()

画像2

"0"とかかれた列に0から100の乱数が引っ付いた。まず、0という名前がダサいのと、列名の頭文字が大文字と小文字が混じっているのが気持ち悪いので、列名を直す。列名は左からID、Score、Timing、Sexとする。

columns=['ID','Score', 'Timing','Sex']
df_all.columns =columns

列名が直っているか確認してみる。

df_all.head()

画像3

うん。いい感じ。

次に。0から100の乱数に対して、50未満だったら男("Man")、50以上だったら女(”Woman”)とラベリングしていく。まずは、仕分けするdef関数を作成する。

def man_women(MW):    
   sex = MW
   if sex < 50:
       return 'Men'
   else:
       return 'Women'

Sex2という新たな列を作成し、ここに上記の関数で振り分けたManとWomanのラベルを格納する。

df_all['Sex2'] = df_all['Sex'].apply(man_women)

中身を確認してみる。

df_all.head()

画像4

性別を上手く振り分けることができた。ここで、x軸にTiminig、y軸にScore、凡例にSex2としてviolinplotを作成してみる。凡例の加え方は、violinplot()のなかにhueの設定をする。今回は、hue="Sex2"とした。

plt.figure(figsize=(20,10))#グラフの大きさ設定
sns.set_style('ticks')#grid腺を消す
sns.violinplot(x="Timing", y="Score", data=df_all, palette="pastel", hue="Sex2")
plt.tick_params(labelsize = 30)#軸ラベルの大きさ
plt.title("Mean", size=50)#グラフのタイトル
plt.ylabel("Score", size=50)#y軸ラベル
plt.xlabel("")#x軸ラベルの消去

画像5

pre、post1、post2のそれぞれに性別のviolinplotを作成できた。次は、性別を合体したviolinplotを作成する。つまり、今現れているManとWomanの二つのviolinplotを一つにする。そのためには、violinplot()にsplit=Trueを追加する。

plt.figure(figsize=(20,10))#グラフの大きさ設定
sns.set_style('ticks')#grid腺を消す
sns.violinplot(x="Timing", y="Score", data=df_all, palette="pastel", hue="Sex2",split=True)
plt.tick_params(labelsize = 30)#軸ラベルの大きさ
plt.title("Mean", size=50)#グラフのタイトル
plt.ylabel("Score", size=50)#y軸ラベル
plt.xlabel("")#x軸ラベルの消去

画像7

成功。すっきりしていい感じ。

次に冒頭で紹介した論文のように時系列のviolinplotに挑戦する。x軸にSex2、y軸にScore、凡例にTiming、split=Trueとしてviolinplotを作成してみる。

plt.figure(figsize=(20,10))#グラフの大きさ設定
sns.set_style('ticks')#grid腺を消す
sns.violinplot(x="Sex2", y="Score", data=df_all, palette="pastel", hue="Timing",split=True)
plt.tick_params(labelsize = 30)#軸ラベルの大きさ
plt.title("Mean", size=50)#グラフのタイトル
plt.ylabel("Score", size=50)#y軸ラベル
plt.xlabel("")#x軸ラベルの消去

画像8

エラーいただきました。ごちそうさまです。

色々と書いてあるけど、まず見るべき点は一番下のValueErroの箇所。そこには、"There must be exactly two hue levels to use `split"との英語が。。。hue(凡例)が二つでないといけないみたい。今回は、pre、post1、post2と凡例が三つあったのでエラーがでたようだ。せっかく作成したデータセットだけど、post2にはいなくなってもらうことにした。

一旦CSVファイルとしてはきだす。はきだしたファイル名をsample3.csvとしておく。

df_all.to_csv("sample3.csv")

CSVファイルを開いて、post2の行をすべて削除する。該当セルをドラッグして「Post2 Good Bye!」と言いながらデリートボタンを押す。あ、「Post2 Good Bye!」は別に言わなくていい。

画像9

上書き保存して、またpythonに読み込む。新たに作成したCSVファイルは↓

df_paper=pd.read_csv('sample3.csv')

先ほどエラーがでたコードをもう一度使用してviolinplotを作成する。

plt.figure(figsize=(20,10))#グラフの大きさ設定
sns.set_style('ticks')#grid腺を消す
sns.violinplot(x="Sex2", y="Score", data=df_paper, palette="pastel", hue="Timing",split=True)
plt.tick_params(labelsize = 30)#軸ラベルの大きさ
plt.title("Mean", size=50)#グラフのタイトル
plt.ylabel("Score", size=50)#y軸ラベル
plt.xlabel("")#x軸ラベルの消去

画像10

エラーがでることなく、男と女それぞれにpreとpost1が合体したviolinplotが作成できた。右端に存在する凡例が見ずらいので、最後に大きくしとく。凡例の調節にはlegend()を用いる。大きさを変えるにはfontsizeで数値を設定する。

plt.figure(figsize=(20,10))#グラフの大きさ設定
sns.set_style('ticks')#grid腺を消す
sns.violinplot(x="Sex2", y="Score", data=df_paper, palette="RdBu_r", hue="Timing",split=True)
plt.tick_params(labelsize = 30)#軸ラベルの大きさ
plt.title("Mean", size=50)#グラフのタイトル
plt.ylabel("Score", size=50)#y軸ラベル
plt.xlabel("")#x軸ラベルの消去
plt.legend(fontsize=20)#凡例サイズの大きさ

画像11

うん。OK。できました。preには平均値30標準偏差20の乱数、post1には平均値50標準偏差15の乱数が入っているので、preにくらべpost1のほうが性別関係なくスコアが高いことが分かる。

あくまでも、このグラフを作成しているのに使っているデータは架空のデータなので、筋トレによってスコアが上がったことを示すグラフではない。このシリーズで示してきた研究デザインは、自分がグラフ作成のイメージを膨らませるために空想したもの。

ちなみに、

Eckardt, N., Braun, C., & Kibele, A. (2020). Instability Resistance Training improves Working Memory, Processing Speed and Response Inhibition in Healthy Older Adults: A Double-Blinded Randomised Controlled Trial. Scientific Reports, 10(1), 1-12.
https://rdcu.be/b2Xa5 

には、Supplementary informationのところに、この研究のデータセットが公開してある。もし興味がある人がいれば、このデータセットを使用して、violinplotが書けるかためしてほしい。

論文のデータセットを使用してグラフを書いてnote等に公開したら、著作権侵害の恐れがあるので自分はしない。そもそも面倒だから、今のところしていない。気が向いたらこっそりグラフを描いてみる。

今日のはviolinplotを作成するために参考にしたwebページや資料(順不同)。
1. seabornによる統計データ可視化(ポケモン種族値を例に)(1)
http://mizti.hatenablog.com/entry/2017/11/18/seaborn1
2. seaborn.violinplot
https://seaborn.pydata.org/generated/seaborn.violinplot.html
3. Choosing color palettes
https://seaborn.pydata.org/tutorial/color_palettes.html
4. Numpyによる乱数生成まとめ
https://qiita.com/yubais/items/bf9ce0a8fefdcc0b0c97
5. 【Pandas入門】DataFrame等の列の名前を指定できるcolumns引数!
https://www.sejuku.net/blog/75495
6. 文字列の基礎知識 – Python3 入門 マニュアル
https://it-engineer-lab.com/python3-manual-strings
7. Pandas でデータフレームから特定の行・列を取得する
https://pythondatascience.plavox.info/pandas/%E8%A1%8C%E3%83%BB%E5%88%97%E3%81%AE%E6%8A%BD%E5%87%BA
8. Python matplotlib 図と凡例のタイトルのフォントサイズを変える
https://qiita.com/damyarou/items/779562cf8bd801e8d147
9. Udemy 【世界で5万人が受講】実践 Python データサイエンス
Lecture 56-59

と今日はこんな感じ。