[Python][Seaborn] Swarmplotが便利
Swarmplotの利点
Seabornライブラリのswarmplotがとても便利、というだけの記事。
import matplotlib.pyplot as plt import seaborn as sns df = sns.load_dataset('iris') fig, ax = plt.subplots() sns.swarmplot(x='species', y='sepal_length', data=df, ax=ax) fig.savefig('sepal_length.jpg', dpi=300) plt.close(fig)
swarmplotを使うと、同じ値が複数あるときに横にずらして並べてくれるので、全体的な傾向が分かりやすい。
この図の場合、sepal_length(花のがくの長さ)の平均は、setosa種<versicolor種<virginica種、という傾向にありそうだが、同時に分散も大きくなっていそうだというのが見てとれる。
Swarmplotの限界
ただしswarmplotにも限界はあって、同じ値を持つデータ数が多くなりすぎると、横にずらすスペースがなくなって、最終的に重なってしまう。
下の図は、先程のデータセットを使ってpetal_length(花弁の長さ)をプロットしたもの。
左のsetosa種では似たような値が多いために、横の方で複数の点が重なってしまっている。そうなると、頻度が分かりにくくなり、swarmplotを使う利点は小さくなる。
もしswarmplotで綺麗に描けないくらい値の似たデータが多いなら、カテゴリごとにヒストグラムを描いて並べるのが良いだろう。ただその場合は、ヒストグラムの切り方(bins)に注意を払う必要がある。
[Python][Pandas] いずれかの文字列と合致するorを含む行を抽出する
はじめに
文字列のリストが用意されていて、PandasのDataFrameからいずれかの文字列と合致するor含む行を取り出したいときがある。
Forループを使えば書けるのだが、Numpyを使えばもっとシンプルに書けることに気づいたのでまとめておく。
テスト用のDataFrameを読み込む
seabornライブラリからirisデータセットを読み込む。
import seaborn as sns df = sns.load_dataset('iris') df.to_csv('iris.csv')
irisデータセットは、文字列の種名を含んでいる。
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa |
5 | 5.4 | 3.9 | 1.7 | 0.4 | setosa |
6 | 4.6 | 3.4 | 1.4 | 0.3 | setosa |
7 | 5.0 | 3.4 | 1.5 | 0.2 | setosa |
8 | 4.4 | 2.9 | 1.4 | 0.2 | setosa |
9 | 4.9 | 3.1 | 1.5 | 0.1 | setosa |
10 | 5.4 | 3.7 | 1.5 | 0.2 | setosa |
11 | 4.8 | 3.4 | 1.6 | 0.2 | setosa |
12 | 4.8 | 3.0 | 1.4 | 0.1 | setosa |
13 | 4.3 | 3.0 | 1.1 | 0.1 | setosa |
14 | 5.8 | 4.0 | 1.2 | 0.2 | setosa |
15 | 5.7 | 4.4 | 1.5 | 0.4 | setosa |
16 | 5.4 | 3.9 | 1.3 | 0.4 | setosa |
17 | 5.1 | 3.5 | 1.4 | 0.3 | setosa |
18 | 5.7 | 3.8 | 1.7 | 0.3 | setosa |
19 | 5.1 | 3.8 | 1.5 | 0.3 | setosa |
20 | 5.4 | 3.4 | 1.7 | 0.2 | setosa |
21 | 5.1 | 3.7 | 1.5 | 0.4 | setosa |
22 | 4.6 | 3.6 | 1.0 | 0.2 | setosa |
23 | 5.1 | 3.3 | 1.7 | 0.5 | setosa |
24 | 4.8 | 3.4 | 1.9 | 0.2 | setosa |
25 | 5.0 | 3.0 | 1.6 | 0.2 | setosa |
26 | 5.0 | 3.4 | 1.6 | 0.4 | setosa |
27 | 5.2 | 3.5 | 1.5 | 0.2 | setosa |
28 | 5.2 | 3.4 | 1.4 | 0.2 | setosa |
29 | 4.7 | 3.2 | 1.6 | 0.2 | setosa |
30 | 4.8 | 3.1 | 1.6 | 0.2 | setosa |
31 | 5.4 | 3.4 | 1.5 | 0.4 | setosa |
32 | 5.2 | 4.1 | 1.5 | 0.1 | setosa |
33 | 5.5 | 4.2 | 1.4 | 0.2 | setosa |
34 | 4.9 | 3.1 | 1.5 | 0.2 | setosa |
35 | 5.0 | 3.2 | 1.2 | 0.2 | setosa |
36 | 5.5 | 3.5 | 1.3 | 0.2 | setosa |
37 | 4.9 | 3.6 | 1.4 | 0.1 | setosa |
38 | 4.4 | 3.0 | 1.3 | 0.2 | setosa |
39 | 5.1 | 3.4 | 1.5 | 0.2 | setosa |
40 | 5.0 | 3.5 | 1.3 | 0.3 | setosa |
41 | 4.5 | 2.3 | 1.3 | 0.3 | setosa |
42 | 4.4 | 3.2 | 1.3 | 0.2 | setosa |
43 | 5.0 | 3.5 | 1.6 | 0.6 | setosa |
44 | 5.1 | 3.8 | 1.9 | 0.4 | setosa |
45 | 4.8 | 3.0 | 1.4 | 0.3 | setosa |
46 | 5.1 | 3.8 | 1.6 | 0.2 | setosa |
47 | 4.6 | 3.2 | 1.4 | 0.2 | setosa |
48 | 5.3 | 3.7 | 1.5 | 0.2 | setosa |
49 | 5.0 | 3.3 | 1.4 | 0.2 | setosa |
50 | 7.0 | 3.2 | 4.7 | 1.4 | versicolor |
51 | 6.4 | 3.2 | 4.5 | 1.5 | versicolor |
52 | 6.9 | 3.1 | 4.9 | 1.5 | versicolor |
53 | 5.5 | 2.3 | 4.0 | 1.3 | versicolor |
54 | 6.5 | 2.8 | 4.6 | 1.5 | versicolor |
55 | 5.7 | 2.8 | 4.5 | 1.3 | versicolor |
56 | 6.3 | 3.3 | 4.7 | 1.6 | versicolor |
57 | 4.9 | 2.4 | 3.3 | 1.0 | versicolor |
58 | 6.6 | 2.9 | 4.6 | 1.3 | versicolor |
59 | 5.2 | 2.7 | 3.9 | 1.4 | versicolor |
60 | 5.0 | 2.0 | 3.5 | 1.0 | versicolor |
61 | 5.9 | 3.0 | 4.2 | 1.5 | versicolor |
62 | 6.0 | 2.2 | 4.0 | 1.0 | versicolor |
63 | 6.1 | 2.9 | 4.7 | 1.4 | versicolor |
64 | 5.6 | 2.9 | 3.6 | 1.3 | versicolor |
65 | 6.7 | 3.1 | 4.4 | 1.4 | versicolor |
66 | 5.6 | 3.0 | 4.5 | 1.5 | versicolor |
67 | 5.8 | 2.7 | 4.1 | 1.0 | versicolor |
68 | 6.2 | 2.2 | 4.5 | 1.5 | versicolor |
69 | 5.6 | 2.5 | 3.9 | 1.1 | versicolor |
70 | 5.9 | 3.2 | 4.8 | 1.8 | versicolor |
71 | 6.1 | 2.8 | 4.0 | 1.3 | versicolor |
72 | 6.3 | 2.5 | 4.9 | 1.5 | versicolor |
73 | 6.1 | 2.8 | 4.7 | 1.2 | versicolor |
74 | 6.4 | 2.9 | 4.3 | 1.3 | versicolor |
75 | 6.6 | 3.0 | 4.4 | 1.4 | versicolor |
76 | 6.8 | 2.8 | 4.8 | 1.4 | versicolor |
77 | 6.7 | 3.0 | 5.0 | 1.7 | versicolor |
78 | 6.0 | 2.9 | 4.5 | 1.5 | versicolor |
79 | 5.7 | 2.6 | 3.5 | 1.0 | versicolor |
80 | 5.5 | 2.4 | 3.8 | 1.1 | versicolor |
81 | 5.5 | 2.4 | 3.7 | 1.0 | versicolor |
82 | 5.8 | 2.7 | 3.9 | 1.2 | versicolor |
83 | 6.0 | 2.7 | 5.1 | 1.6 | versicolor |
84 | 5.4 | 3.0 | 4.5 | 1.5 | versicolor |
85 | 6.0 | 3.4 | 4.5 | 1.6 | versicolor |
86 | 6.7 | 3.1 | 4.7 | 1.5 | versicolor |
87 | 6.3 | 2.3 | 4.4 | 1.3 | versicolor |
88 | 5.6 | 3.0 | 4.1 | 1.3 | versicolor |
89 | 5.5 | 2.5 | 4.0 | 1.3 | versicolor |
90 | 5.5 | 2.6 | 4.4 | 1.2 | versicolor |
91 | 6.1 | 3.0 | 4.6 | 1.4 | versicolor |
92 | 5.8 | 2.6 | 4.0 | 1.2 | versicolor |
93 | 5.0 | 2.3 | 3.3 | 1.0 | versicolor |
94 | 5.6 | 2.7 | 4.2 | 1.3 | versicolor |
95 | 5.7 | 3.0 | 4.2 | 1.2 | versicolor |
96 | 5.7 | 2.9 | 4.2 | 1.3 | versicolor |
97 | 6.2 | 2.9 | 4.3 | 1.3 | versicolor |
98 | 5.1 | 2.5 | 3.0 | 1.1 | versicolor |
99 | 5.7 | 2.8 | 4.1 | 1.3 | versicolor |
100 | 6.3 | 3.3 | 6.0 | 2.5 | virginica |
101 | 5.8 | 2.7 | 5.1 | 1.9 | virginica |
102 | 7.1 | 3.0 | 5.9 | 2.1 | virginica |
103 | 6.3 | 2.9 | 5.6 | 1.8 | virginica |
104 | 6.5 | 3.0 | 5.8 | 2.2 | virginica |
105 | 7.6 | 3.0 | 6.6 | 2.1 | virginica |
106 | 4.9 | 2.5 | 4.5 | 1.7 | virginica |
107 | 7.3 | 2.9 | 6.3 | 1.8 | virginica |
108 | 6.7 | 2.5 | 5.8 | 1.8 | virginica |
109 | 7.2 | 3.6 | 6.1 | 2.5 | virginica |
110 | 6.5 | 3.2 | 5.1 | 2.0 | virginica |
111 | 6.4 | 2.7 | 5.3 | 1.9 | virginica |
112 | 6.8 | 3.0 | 5.5 | 2.1 | virginica |
113 | 5.7 | 2.5 | 5.0 | 2.0 | virginica |
114 | 5.8 | 2.8 | 5.1 | 2.4 | virginica |
115 | 6.4 | 3.2 | 5.3 | 2.3 | virginica |
116 | 6.5 | 3.0 | 5.5 | 1.8 | virginica |
117 | 7.7 | 3.8 | 6.7 | 2.2 | virginica |
118 | 7.7 | 2.6 | 6.9 | 2.3 | virginica |
119 | 6.0 | 2.2 | 5.0 | 1.5 | virginica |
120 | 6.9 | 3.2 | 5.7 | 2.3 | virginica |
121 | 5.6 | 2.8 | 4.9 | 2.0 | virginica |
122 | 7.7 | 2.8 | 6.7 | 2.0 | virginica |
123 | 6.3 | 2.7 | 4.9 | 1.8 | virginica |
124 | 6.7 | 3.3 | 5.7 | 2.1 | virginica |
125 | 7.2 | 3.2 | 6.0 | 1.8 | virginica |
126 | 6.2 | 2.8 | 4.8 | 1.8 | virginica |
127 | 6.1 | 3.0 | 4.9 | 1.8 | virginica |
128 | 6.4 | 2.8 | 5.6 | 2.1 | virginica |
129 | 7.2 | 3.0 | 5.8 | 1.6 | virginica |
130 | 7.4 | 2.8 | 6.1 | 1.9 | virginica |
131 | 7.9 | 3.8 | 6.4 | 2.0 | virginica |
132 | 6.4 | 2.8 | 5.6 | 2.2 | virginica |
133 | 6.3 | 2.8 | 5.1 | 1.5 | virginica |
134 | 6.1 | 2.6 | 5.6 | 1.4 | virginica |
135 | 7.7 | 3.0 | 6.1 | 2.3 | virginica |
136 | 6.3 | 3.4 | 5.6 | 2.4 | virginica |
137 | 6.4 | 3.1 | 5.5 | 1.8 | virginica |
138 | 6.0 | 3.0 | 4.8 | 1.8 | virginica |
139 | 6.9 | 3.1 | 5.4 | 2.1 | virginica |
140 | 6.7 | 3.1 | 5.6 | 2.4 | virginica |
141 | 6.9 | 3.1 | 5.1 | 2.3 | virginica |
142 | 5.8 | 2.7 | 5.1 | 1.9 | virginica |
143 | 6.8 | 3.2 | 5.9 | 2.3 | virginica |
144 | 6.7 | 3.3 | 5.7 | 2.5 | virginica |
145 | 6.7 | 3.0 | 5.2 | 2.3 | virginica |
146 | 6.3 | 2.5 | 5.0 | 1.9 | virginica |
147 | 6.5 | 3.0 | 5.2 | 2.0 | virginica |
148 | 6.2 | 3.4 | 5.4 | 2.3 | virginica |
149 | 5.9 | 3.0 | 5.1 | 1.8 | virginica |
DataFrameからある一つの文字列と合致する行を取り出す
DataFrameからある一つの文字列と合致する行を取り出すには、次のように書けば良い。
import seaborn as sns df = sns.load_dataset('iris') df_setosa = df[df['species'] == 'setosa'].copy() df_setosa.to_csv('setosa.csv')
これで種名が'setosa'の行だけを取り出すことができる。
DataFrameから複数の文字列のいずれかと合致する行を取り出す
irisデータセットから、種名が'setosa'あるいは'virginica'である行だけを取り出したい。
この場合、Numpyのanyメソッドを使うとシンプルに書くことができる。
import numpy as np import seaborn as sns df = sns.load_dataset('iris') species_list = ['setosa', 'virginica'] df_se_vi = df[ np.array([df['species'] == aspecies for aspecies in species_list]).any(axis=0) ].copy() df_se_vi.to_csv('setosa_virginica.csv')
この書き方の場合、species_listの要素数が増減しても変更の必要がないというメリットがある。
DetaFrameから複数の文字列のいずれかを含む行を取り出す
条件式の==
をstr.contains
メソッドに変えれば良い。
import numpy as np import seaborn as sns df = sns.load_dataset('iris') part_list = ['set', 'vir'] df_set_vir = df[ np.array([df['species'].str.contains(part) for part in part_list]).any(axis=0) ] df_set_vir.to_csv('set_vir.csv')
Wikipedia「Narrative structure」の和訳
少し興味を持ったので、訳しつつ読んでみた。感想としては、分類のセクションはなるほどと思ったが、他の箇所は話がつぎはぎで得るものは少なかったかなという印象。
原文はこちら(2020年6月27日版)。
en.wikipedia.org
注意
- ざっくり和訳なので厳密な訳ではありません。
- とくに専門用語に関しては不自然な和訳をしている可能性があります。
====================
物語構造 Narrative Structure
物語構造は文学の要素であり、一般には、物語が読者・聞き手・視聴者に提示される際の順序と方法の基礎をなす構造的枠組みとして記述される。物語のテキストの構造は、プロットと背景である。
目次
1. 定義 Definition
物語構造はストーリーとプロット、すなわちストーリーの内容とストーリーを伝えるために使われる形式に関するものである。ストーリーは、時系列順に記述された劇中の出来事を表す。プロットは、ストーリーがどのように伝えられるかを表す。ストーリーは重大な対立や主要な登場人物、背景や出来事を決定するもののことである。プロットはどのように、どの段階で、重大な対立が生じ、そして解消されるかについてである。
2. 説明 Description
第一幕では、すべての主要な登場人物と彼らの基本的な状況が紹介され、最も基本的な人物描写が含まれる。ある問題が導入され、これが物語を推し進めていく。
第二幕は物語の主要部分であり、ある出来事が物事を動かしていく。出来事の結果として、登場人物は人生における大きな変化を経験する。これはキャラクターアーク(訳者注:登場人物の変化のこと?)と呼ばれる。
第三幕では、ストーリーにおける問題が進展し、登場人物はその問題に直面せざるをえなくなる。ストーリーの全ての要素がうまくいき、必然的にエンディングへと向かう。
3. 歴史 History
物語構造の概念は最初に古代ギリシャの哲学者によって記述された。20世紀中期~後期に、ロラン・バルト、ウラジーミル・プロップ、ジョーゼフ・キャンベル、ノースロップ・フライといった構造主義文学研究者らが、すべての人間の物語がある普遍的で深い構造を持っているという議論を試み、その中で物語構造は重要な概念として見直された。ミシェル・フーコーやジャック・デリダなどのポスト構造主義の支持者は、そのように普遍的に共有された深い構造は論理的に不可能であると主張し、この論争の流行は終わった。
『批評の解剖』(Anatomy of Criticism)でノースロップ・フライは彼が春、夏、秋、冬の神話と呼んだものについて広範に取り扱っている。
- 春の神話は喜劇である。悪い状況から幸福な結末へと導くストーリーである。シェークスピアの『十二夜』など。
- 夏の神話は同様に理想郷的ファンタジーである。ダンテの『天国篇』など。
- 秋の神話は、理想的な状況から災難に至るような悲劇である。『ハムレット』、『オセロ』、『リア王』、映画『レジェンド・オブ・フォール』など。
- 冬の神話はディストピアである。ジョージ・オーウェルの『1984』、オルダス・ハクスリーの『すばらしい新世界』、アイン・ランドの『アンセム』など。
※訳者補足:春の神話(悪⇒良)、夏の神話(良⇒良)、秋の神話(良⇒悪)、冬の神話(悪⇒悪)、ということだろうか?
4. 分類 Categories
物語の多くの形式は、四つの主要なカテゴリのどれかに入る。
- 線形な物語は、最も普遍的な叙述である。ここでは出来事はおおよそ時系列順に表現される。すなわち、出来事は起こった順に説明される。
- 非線形な物語(分裂した物語、分断された物語)では、出来事が時系列とは異なる順序で説明されたり、直接的な因果関係を追わないような方法で説明されたりする。
- インタラクティブな叙述は、読者によって動き出す線形な物語作品のことを指す。
- インタラクティブな物語は、読者が物語に影響を与えるような選択が可能なフィクションの形式のことである。例えば、読者の選択によって、別のプロットや別の結末にたどり着いたりする。
4.1 線形な物語 Linear narrative
回想は線形でない真の物語とよく混同されるが、回想の構造は基本的に線形である。オーソン・ウェルズの『市民ケーン』が一例である。いくつかの映画は結末から始まるが、回想映画はほとんど即座にストーリーの最初に戻り、そこから線形にストーリーが進んでいき、通常は映画の冒頭で見た結末と思われる過去まで進行する。
4.2 非線形な物語 Nonlinear narrative
映画は壊れた物語を通して単なる幻想(訳者注:錯覚?幻影?)を提示することもでき、その有名な例が1994年のパルプフィクションである。この映画は表向きには三つの短いストーリーからなり、これらは時系列的が崩壊した一つのストーリーの三つのセクションをなす。クエンティン・タランティーノは、古典的なフラッシュバックのテクニックを使うことなく、物語を構築したのである。
非線形な物語をもとに映画を制作するというさらなる野心的な試みに、1993年のAlain Resnaisによるフランス映画『Smoking/No Smoking』がある。この映画のプロットには、並行した展開が含まれており、登場人物が異なる選択をした場合のアイデアのもとで進行する。
映画の他には、いくつかの小説も非線形な方法で物語を表現している。Creative writingの教授Jane Alisonは2019年の本『Meander, Spiral, Explode: Design and Pattern in Narrative』のなかで、非線形な物語のパターンとして、螺旋、波、湾曲といったものを説明している。Chitra Banerjee Divakaruniの小説『Before We Visit the Goddess』の章は、出来事は線形な順序ではなく、むしろ特定の文学的手法を実現するような順序で整理されている。これにより、ストーリーをより面白くなるだけでなく、小説の中の登場人物は信用できる一生のタイムラインを持つことになる。
4.3 インタラクティブな叙述 Interactive narration
インタラクティブな叙述の作品では、たった一つの物語が存在するが、ユーザーは物語の次のピースを手に入れるため、あるいは筋が通った物語を組み立てるため、ユーザーは能動的に動かなければならない。
これは現代のビデオゲームに見られるような物語の手法である。プレイヤーは物語を進行させるため、ある目標を達成したり、ある作業を完遂したり、あるパズルを解いたり、あるレベルを終えたりしなければならない。
4.4 インタラクティブな物語 Interactive narrative
インタラクティブな物語は、枝分かれ構造をからなり、始まりの状況から複数の進展や結末に繋がる。そのような全てのゲームの原則は、物語のいずれの段階においても、ユーザーが選択することでストーリーが進展し、それによってまた新たな一連の選択肢が生まれるということである。このように、非線形な物語や会話を書くには、並行する多数の定まらないストーリーの存在を想像する必要がある。
ゲームブックでは、読者はストーリーを続けるためにした選択に基づき、特定のページを開くように指示される。典型的には、選択肢は会話ではなく行動である。例えば、主人公は別の部屋から物音を聞き、ドアを開けて調べるか、または逃げるか、あるいは助けを呼ぶかキメなければならない。この種のインタラクティブな体験は、ビデオゲームや本で可能だが、他の形式の娯楽にはあまり適さない。即興劇は同様に自由だが、もちろん「即興劇を書く」とは言わない。
5 図的な物語
漫画などに見られるシンプルな図的物語には、四つの段階がある。
- 登場人物の紹介と状況の説明
- 問題の導入、予期せぬチャンス、または状況の複雑化
- 一人または複数人の登場人物が問題に対して部分的または完全に対応する形での問題の解消
- 問題への対応によって明白な成功、部分的成功、不成功、不確かな成功が生じる(大団円、結末)
この四つの段階は、物語の複雑化と解決の段階にとって代わる物によって元々の状況がどのように変化したかを示しているのかもしれない(訳者注:この一文は意味がとれなかった)。
単純な物語では、この四つの段階は順に現れる。つまり、出来事は時系列順に説明される。より複雑なストーリーでは、出来事が説明される順序は変化する。実際に、そのようなストーリーは、大団円やその後の現在の状況、複雑化、回想における解決から始まることがある。しかし、これはシンプルな物語の場合とは異なる。
6. 関連項目
- Dramatic structure
- Narratology
- Narreme as the basic unit of narrative structure
- Non-narrative film
- Rising action
- Suspense
- Three-act structure
7. 参考文献・資料
(省略)
[Python][Pandas] Pandasの基本用法まとめ
環境:Windows10 + Anaconda 4.8.1 + Python 3.7 + Pandas 1.0.5
目次
はじめに
PythonにはPandasというデータ分析用のライブラリがある。使いこなせれば、CSVファイルなど表形式のデータからいろいろな情報を引き出すことができる。
一方で、Pythonの基本文法とは異なる、ライブラリ特有の文法に関する知識が必要なため、最初のハードルは決して低くないように思う。Pandasの文法は、Pythonの基本文法と違うだけでなく、Numpyとも違い、Rとも違うと感じる。ゆえに直観的に理解しづらい。
そこでこのページでは、Pandasの基本的な用法をまとめることにする。自分の勉強も兼ねている部分があるので、足りない部分やまだ分からない部分もあるが、随時書き足していけたらと思う。
準備
インストール
Anaconda環境の場合は
conda install pandas
としてインストールする。
バージョン
大きく二つのバージョンが存在する。
- ver0.25系(記事執筆時点では0.25.3が最新)
- ver1.0系(記事執筆時点では1.0.5が最新)
pandas.pydata.org
pandas.pydata.org
バージョン1.0.0がリリースされたのは2020年1月29日と比較的最近のことであり(記事執筆時点においては)、ver0.25系を用いているプログラムもまだまだ多いと思われる。ver1.0では一部の機能が削除されており、公式ドキュメントではver0.25からver1.0に更新する前にソースコードが警告なしで作動するか確認するようにとアナウンスしている*1。
新しくインストールする場合は、ver1.0をインストールすればよい。すでにインストール済みの場合は、更新する前に確認することをおすすめする(仮想環境を新たに作成するのも一つの手)。
インポート
import pandas as pd
とするのが一般的。
サンプルデータ
Pandasの機能を試すために、サンプルデータを使いたいときがある。しかし調べた限りでは、Pandasにはサンプルデータは含まれていなかった。そこで代わりにseabornライブラリから読み込むことにする。
seaborn.load_dataset('iris') # --> pandas.DataFrame
ここではseabornライブラリからiris(アヤメ)のデータを読み込んでいる。seabornライブラリから読み込んでも、pandasのDataFrameで返してくれる。
Pandasの型
Pandasには多数の型があり、把握するだけでも一苦労である。Pandasの型については次のページが詳しい。
https://pbpython.com/pandas_dtypes.html
note.nkmk.me
ここでは使用頻度の高そうな型にしぼって取り上げる。
- DataFrame:データフレーム。データセットは主にこの型で処理される。
- Series:シーケンス。Seriesが集まったものがDataFrameである。
- 要素:シーケンスの要素にはいろいろな型がある。主なものを以下に列挙する。
- int64:整数
- float64:倍精度浮動小数点
- bool:ブール値
- object:文字列または型の混合
- datetime64:日付を表す
- timedelta:時間差を表す
- category:カテゴリカルなデータを表す
いま扱っている変数はDataFrameかSeriesか要素か、要素であれば何の型か、を意識しながらプログラムを書くことになる。
データフレームの作成
いくつかの方法があるが、最も簡単な方法を一つ示す。
pandas.DataFrame( data, columns=['column0', 'column1', 'column2'], dtype={'column0': 'float', 'column1': 'int', 'column2': 'object'} )
作成したリスト内リスト(行列)を、pandasのDataFrameに変換する。列名をcolumns引数で指定し、各列の型をdtype引数に辞書で指定する(オプション)。
CSVファイルの読み込み・書き出し
Pandasでデータを処理するにあたって、CSVファイルは最も基本となるファイルの一つ。DataFrameをCSVで保存したり、CSVからDataFrameを読み込んだりする。
Seriesの基本操作
DataFrameから一列取り出すとSeriesになる。まずはSeriesから要素を取り出す方法を示す。
pandas.Series.at[label]など
pandas.Series.at[label] # -> 要素 pandas.Series.iat[n] # -> 要素 pandas.Series.loc[label1:label2] # -> pandas.Series pandas.Series.iloc[n1:n2] # -> pandas.Series
以上の四つの方法では、「取り出すもの」と「要素の指定方法」に違いがある。
取り出すもの | 要素の指定方法 | |
---|---|---|
at |
単独の要素 | ラベル(インデックス) |
iat |
単独の要素 | 整数 |
loc |
複数の要素 | ラベル(インデックス) |
iloc |
複数の要素 | 整数 |
ラベルを使って指定するか整数を使って指定するかという違いはあるが、おそらく多くのSeriesではラベルが整数であるため(つまりlabelが整数)、どちらを使っても同じにはなる。ただし、iloc
では最後の値(n2
)を含まないのに対し、loc
では最後の値(label2
)を含むことに注意する必要がある。
とは言え、上記四つの方法を目的に応じて使い分けるのはやや面倒なので、巨大なデータでなければnumpy.ndarrayやlistに変換してから要素にアクセスするの方が、間違いがなくて良いと思う。
numpy.ndarrayやlistに変換する方法を示す。
pandas.Series.values -> numpy.ndarray
Seriesをnumpy.ndarrayに変換して返す。
pandas.Series.to_list() -> [Any, ...]
Seriesを標準Pythonのリストに変換して返す。values
はインスタンス変数だが、to_list
はメソッドであることに注意。
pandas.Series.index.values -> numpy.ndarray
Seriesのラベル(インデックス)を返す。たいていは[0, 1, 2, ...]という整数のシーケンス。最後にvaluesを着けない場合は、イテラブルなpandas.RangeIndexというオブジェクトが返される。
Seriesの長さや要素の型は、インスタンス変数に入っている。
pandas.Series.size -> int
Seriesが持つ要素の数を返す。配列の長さと同じ。
pandas.Series.dtype -> numpy.dtype
要素の型を返す.
DataFrameの基本操作
pandas.DataFrame.at[label_row, label_col]など
pandas.DataFrame.at[label_row, label_col] # -> 要素 pandas.DataFrame.iat[n_row, n_col] # -> 要素 pandas.DataFrame.loc[label1_row:label2_row, label1_col:label2_col] # -> pandas.DataFrame pandas.DataFrame.iloc[n1_row:n2_row, n1_col:n2_col] # -> pandas.DataFrame
Seriesの場合と同様に、atとiatは単独の要素を取得するのに対し、locとilocは複数の要素(この場合はDataFrame)を取得する。atとlocはラベル(インデックス)を用いて、iatとilocは整数を用いて位置を指定する。
pandas.DataFrame.head(n=5) -> pandas.DataFrame
データフレームの先頭n行を返す(デフォルトでは5行)。printして中身を確認するといった用途に。
pandas.DataFrame.columns.values -> numpy.ndarray
列名をリストで取得する。
pandas.DataFrame.index.values -> numpy.ndarray
行名をリストで取得する。
pandas.DataFrame['column'] -> pandas.Series
列名columnのSeriesを取得する。
イテレーション
pandas.DataFrame.iterrows() -> Iterable
Indexとrowのtupleを返すイテラブル。rowはpandas.Seriesに変換されている。データにはrow[‘column’]という形でアクセス可能。ただしこのメソッドは遅いので、可能ならば次のメソッドを使う方が良い。
pandas.DataFrame.itertuples() -> Iterable
一行ずつ返すイテラブル。行はPandasという名前のnamedtupleに変換されている。データにはrow[0]またはrow.columnといった形でアクセス可能。
Seriesをそのまま使う
Seriesはそれ自体イテラブルになっている。DataFrame全体ではなく、特定のcolumnだけが必要ならば、columnを指定してSeriesで回した方が早い。
速度比較
イテレーションの処理速度比較については次のページが詳しい.
note.nkmk.me
条件抽出
pandas.Series.isin(values) -> pandas.Series
Seriesの各要素がvalueに指定した集合またはシーケンスに含まれるかどうかを判定し、bool値のSeriesを返す。
要素カウント
pandas.Series.unique() -> numpy.ndarray
Seriesに含まれる要素のシーケンスを返す。値の重複はなく、Python組み込みの集合のようなもの。
pandas.Series.value_counts() -> pandas.Series
Seriesに含まれる要素とその出現回数をSeriesで返す。indexに要素の値が、valueに要素の出現回数が入る。Seriesだと扱いにくいという場合は、次のメソッドが便利。
pandas.Series.value_counts().to_dict() -> Dict[Any, int]
Seriesに含まれる要素とその出現回数を辞書で返す。
警告
SettingWithCopyWarning
条件やスライスで抽出したDataFrameは、コピーではなく参照を返すことがある。その参照に対して代入など中身を変更する処理を行うとこの警告が発生する。参照ではなく値を返してほしい場面では、pandas.DataFrame.copy()
を使ってちゃんとコピーを受け取るようにすれば、警告はでなくなる。
[Python][Matplotlib] 変な形のアトラクターをつくる差分方程式系を適当に探してみる
差分方程式系を作る
二変数の差分方程式系を作れば良いので、つまりは
の形式であれば何でも良いということになる。しかし、大抵の写像は平衡点に収束するか爆発するかである。手を動かしていろいろな写像を作ってみると、「平衡点に収束しないが爆発もしない」という微妙なさじ加減がなかなかむずかしいとわかった。
そこで方針を変えて、既存の写像をちょっと変えて新たな写像を作ることにする。ここではロジスティック写像に変更を加えることにした。ロジスティック写像は次のような一変数の差分方程式。
ロジスティック写像は生物の個体数の変化を記述する数理モデルでもある。その場合、 は一個体が最大で生む子の数を表す。個体数が増えてくると、餌や住み場所がなくなるので、生物は増えにくくなる。この混み合いの効果は負の二次項によって表現されている。
ロジスティック写像をもとに、次のような差分方程式系を作ってみた。
も もロジスティック写像に似たような格好になっているが、二次項の部分に和 が入っているのがポイントである。後で示すパラメータでは となっている。ロジスティック写像がそうであったように、生物の個体数変化に即して考えると、 は増えるのは早いが他個体から負の影響を受けやすく、 は増えるのはゆっくりだが他個体からの負の影響を受けにくいという構造になっており、それでうまくバランスして2種の生物が共存してくれることを期待した。
作図する
最初に1000回計算した後で、 回計算して点を打つ方法で作図した。パラメータ と の値をいろいろいじってみたが、 のときが面白かった。
なんだか奇妙な形の範囲で点が動きつづけていることがわかる。大きく見て、上と下の二つ領域があるようにも見える。 のときの図を見ると、真ん中に大きな穴が二つあり、この領域には点が移動しないこともわかる(理屈はわからないが・・・)。
定量的な話をすると、xの値はときどき負の値をとっている。このことは、いま指定したパラメータ()では、この差分方程式を生物の個体数変化として解釈することはできないといういことを意味する。「うまくバランスして2種の生物が共存してくれることを期待した」のだが、少なくともいま指定したパラメータ()に関しては、この企みは失敗したわけである。ロジスティック写像では、 が不安定平衡点になっていて、 が負の値に突入すると は常に負になるので、はどんどん小さくなってに発散してしまうはずである。今回の差分方程式系でも同じようにに発散してしまうかと思いきや、なぜか 周辺に戻ってきている。
もう少し様子を見るために、次のような三次元の差分方程式に直して作図してみる。
式中のという値がポイントになると思ったので、これを各時刻で計算して、第三軸にプロットした。形が理解しやすいよう、z軸で回転したGIFアニメーションを作成した。
点の集合はひしゃげた長方形の形をしているようにも見える。z軸で上側の部分と下側の部分で大きく二つに分かれており、その間を行き来するルートが複数あるのが分かる。この図をz軸でつぶして上から見たのが最初の二次元の図であるから、xy平面で見たときに上と下の2領域があるという見立ては間違いではなかったことになる。
安定性解析
平衡点
がともに0でない平衡点なら
が成り立つ。ここで について整理すると
となる。この等式は特殊なパラメータのときでないと満たされない。当然、 では満たされない。したがって、ともに0でない平衡点 は存在しない。
適当に手計算をすると、平衡点は次の三つであることが分かる。
ソースコード
2次元
from tqdm import tqdm import matplotlib.pyplot as plt import numpy as np x0 = 0.5 y0 = 0.5 N = 10000 N_run = 1000 FILENAME = 'data.csv' a = 3.65 b = 3.6 def func(x, y): x_next = a * x * (1 - (x + y) / 2) y_next = b * y * (1 - (x + y) / 3) return (x_next, y_next) def calc(): x, y = (x0, y0) with open(FILENAME, mode='w') as f: for _ in range(N_run): x, y = func(x, y) for _ in tqdm(list(range(N))): f.write('{:f}, {:f}\n'.format(x, y)) x, y = func(x, y) return def plot_matplotlib(filename): data = np.loadtxt(FILENAME, delimiter=',') fig = plt.figure() ax = fig.add_subplot() ax.scatter(x=data[:, 0], y=data[:, 1], s=0.5, color='C0', antialiased=True) fig.savefig(filename, dpi=600) plt.close(fig) return def main(): calc() plot_matplotlib(filename='figure_a{:.2f}_b{:.2f}_N{:.1e}.jpg'.format(a, b, N)) return if __name__ == '__main__': main()
3次元
import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # NOQA import matplotlib.animation as animation import numpy as np from tqdm import tqdm x0 = 0.5 y0 = 0.5 N = 10000 N_run = 1000 FILENAME = 'data.csv' a = 3.65 b = 3.6 def func(x, y): x_next = a * x * (1 - (x + y) / 2) y_next = b * y * (1 - (x + y) / 3) z_next = x + y return (x_next, y_next, z_next) def calc(): x, y, z = (x0, y0, 0) with open(FILENAME, mode='w') as f: for _ in range(N_run): x, y, z = func(x, y) for _ in tqdm(list(range(N))): f.write('{:f}, {:f}, {:f}\n'.format(x, y, z)) x, y, z = func(x, y) return def plot_gif(): data = np.loadtxt(FILENAME, delimiter=',') fig = plt.figure() ax = fig.add_subplot(111, projection='3d') def plot(angle): ax.scatter(xs=data[:, 0], ys=data[:, 1], zs=data[:, 2], s=0.5, color='C0', antialiased=True) ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') ax.view_init(10, angle) anim = animation.FuncAnimation( fig, plot, interval=300, repeat_delay=2000, frames=np.arange(0, 360, 10) ) anim.save('anim_a{:.2f}_b{:.2f}_N{:.1e}.gif'.format(a, b, N), writer="imagemagick") plt.close(fig) return def main(): calc() plot_gif() return if __name__ == '__main__': main()
CSVの表→はてな記法コンバータ
CSVデータの入力
変換結果(はてな記法)
ここに変換結果が出力されます
使い方
CSV形式の表をはてな記法の表に変換するコンバータを試しに作ってみた(バグあるかも)。
- CSVファイルを用意する(Excelファイルからの作り方は後述)
- CSVファイルのテキストデータを上のボックスに貼り付ける
- チェックボックスで行・列タイトルの有無を設定する
- 「変換実行」ボタンを押す
- 変換結果のテキストをはてなブログの編集画面に貼る
ExcelファイルからCSVファイルを作る方法
Excelの表を変換したい場合は次の手順でCSV形式のテキストが得られる(Windows10環境の場合)。
関連記事
[Python][Matplotlib] 色の形式を変換する
環境
Windows10 + Python 3.7.6 + Matplotlib 3.1.1
maptlotlib.colors
モジュールには、色を表現する変数を変換する関数が用意されており、なかなか便利そうだったのでまとめてみた。
HSV(0~1)からRGB(0~1)へ
hsv_to_rgb(hsv)
例
import matplotlib.colors as mcolors color_hsv = (0, 1, 1) color_rgb = mcolors.hsv_to_rgb(color_hsv) print(color_rgb)
[1. 0. 0.]
RGB(0~1)からHSV(0~1)へ
rgb_to_hsv(rgb)
例
import matplotlib.colors as mcolors color_rgb = (1, 0, 0) color_hsv = mcolors.rgb_to_hsv(color_rgb) print(color_hsv)
[0. 1. 1.]
RGB(0~1)から16進数へ
to_hex(c[, keep_alpha])
- 引数
- c : RGBに対応する長さ3のシーケンスなど
- 返り値
- hex : 16進数の文字列
例
import matplotlib.colors as mcolors color_rgb = (1, 0, 0) color_hex = mcolors.to_hex(color_rgb) print(color_hex)
#ff0000
16進数からRGB(0~1)へ
to_rgb(c)
- 引数
- c : 16進数の文字列など
- 返り値
- rgb : RGBに対応する長さ3のシーケンス
例
import matplotlib.colors as mcolors color_hex = '#ff0000' color_rgb = mcolors.to_rgb(color_hex) print(color_rgb)
(1.0, 0.0, 0.0)
Matplotlibで名前の付いている色の一覧の取得
get_named_colors_mapping()
- 引数:なし
- 返り値
- matplotlib.colors._ColorMapping:色の名前と16進数表記が対応づけられた辞書のようなオブジェクト
例
import matplotlib.colors as mcolors named_colors = mcolors.get_named_colors_mapping() print(named_colors['red']) print(named_colors['xkcd:rust brown'])
#FF0000 #8b3103
メモ:matplotlib.colors._ColorMappingについて
このオブジェクトについて公式ドキュメントで説明を見つけられなかったので、実装を見に行ったところ、次のようなコードを見つけた。ほとんど組み込みの辞書と変わらないオブジェクトと思われる。
class _ColorMapping(dict): def __init__(self, mapping): super().__init__(mapping) self.cache = {} def __setitem__(self, key, value): super().__setitem__(key, value) self.cache.clear() def __delitem__(self, key): super().__delitem__(key) self.cache.clear()
ちなみにget_named_colors_mapping()
は次のように実装されていた。_colors_full_map
変数を返すだけ。_colors_full_map
変数ははじめは組み込みの辞書だが、最後に_ColorMapping
オブジェクトに変換されている。
_colors_full_map = {} # Set by reverse priority order. _colors_full_map.update(XKCD_COLORS) _colors_full_map.update({k.replace('grey', 'gray'): v for k, v in XKCD_COLORS.items() if 'grey' in k}) _colors_full_map.update(CSS4_COLORS) _colors_full_map.update(TABLEAU_COLORS) _colors_full_map.update({k.replace('gray', 'grey'): v for k, v in TABLEAU_COLORS.items() if 'gray' in k}) _colors_full_map.update(BASE_COLORS) _colors_full_map = _ColorMapping(_colors_full_map) def get_named_colors_mapping(): """Return the global mapping of names to named colors.""" return _colors_full_map