124
92

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Python PandasのSeries、Dataframeの基本操作(1)

Last updated at Posted at 2016-12-23

pythonでデータ分析するとき、pandasというモジュールを使うのが一般的である(らしい)。

pandasにおいて、データはSeriesやDataframeという型に収納できる。
Seriesは一次元、Dataframeは二次元のデータを収納するために使われる。
それぞれ、高機能の一次元の配列、二次元の配列のようなものである。
高機能というのは、横行や縦列にそれぞれ名前が付けられる他、多くのメソッドが用意されているのだ。

# ハチマン ユキノ ユイ
数学 8 90 10
国語 88 100 50
英語 38 95 35

二次元配列でこれを表現するとき、「ハチマン」「ユキノ」「ユイ」や「数学」「国語」「英語」といった文字の扱いに困る。Dataframeではこれをcolumnsやindexで表せる。

しかし、この型はいろいろと厄介な仕様があり、私はのっけから躓いてしまった。
これはpandas超初心者の私が自分用に作った、超初歩的なpandas操作マニュアルである。
pythonのバージョンは3.5.2(標準pythonではなく、Anacondan4.2.0を使っている)
pandasのバージョンは0.18.1
コードはiPython5.1.0で実行している状況をイメージしている。

#pandasを使う前の準備
##pandasのインストール
私はAnacondaで一括で入れた。(Anacondaはpython+よく使われるライブラリみたいなものである。NumpyやiPythonも入れられる)
そのほかにも、pipやなんやで入れてもいい。

##pandasのインポート
pandasはモジュールであるため、インポートしなければならない。
In[1]: import pandas
しかし、どこの参考サイトを見ても、pandasはpdという名前で読み込まれているようであるから、ここでもそれに倣う。
In[2]: import pandas as pd

#Seriesの操作
##Seriesを作る
|#|ハチマン|
|:-:|:-:|:-:|:-:|
|数学| 8| 90| 10|
|国語| 88|100| 50|
|英語| 38| 95| 35|
例えば、こんな一次元の配列が与えられたとしよう。
まず、これを見て思いつくのは、Listを作ることである。

In[3]: HachimanList = [8, 88, 38]

これの要素にアクセスするのは簡単だ。
国語の点数がほしいのであれば、
In[4]: Hachiman[1]とすれば
Out[4]: 88と返ってくるだろう。

これの問題点は、「数学」の点数、といった情報が抜けてしまうことだ。
もちろん、辞書を作ったり、オブジェクトを作ったり、名前付きタプルを作ったりしてもいいが、いずれも大規模データ処理には向かない趣がある。

これを解決するのが、pandasのSeriesである。

In[5]: HachimanSeries = pd.Series(HachimanList, index = ["math", "japanese", "english"])

このように、

変数 = pd.Series(データの配列, index = 横行の名前の配列)

で指定できる。
これを出力してみると、

In[6]: HachimanSeries
Out[6]: 
math         8
japanese    88
english     38
dtype: int64`

とそれぞれの項目に名前を与えられて、出力されているのがわかる。
なおdtypeは配列全体のデータ型である。(Numpyで整数型はいくつかの種類の異なる整数型に割り振られる。int64はその内の一つである)

indexを指定していなかったらどうなるのだろうか?エラーが返ってくるのだろうか?

In[7]: YukinoSeries = pd.Series([90, 100, 95]) 
In[8]: YukinoSeries
Out[8]: 
0     90
1    100
2     95
dtype: int64

どうやら、indexは0から増えていくデフォルト値が設定されているようだ。
なお、indexは後から加えることができる。

In[9]: YukinoSeries.index = ["math", "japanese", "english"]
In[10]: YukinoSeries
Out[10]: 
math         90
japanese    100
english      95
dtype: int64

辞書を用いる方法もある。

In[11]: YuiSeries = pd.Series({"math":10, "japanese":50, "english":35})
In[12]: YuiSeries
Out[12]: 
english     35
japanese    50
math        10
dtype: int64

この場合、順番がバラバラになってしまうのは仕方ない。

##Seriesの値を取り出す
Series内の値を取り出すのは通常の配列と殆ど操作が変わらない。
####要素の指定
配列のn番目の要素は配列[n-1]で取り出す。
同様に、Seriesのn番目の要素は

In[13]: HachimanSeries[2]
Out[14]: 38

また、これを変数に渡して、計算することも可能だ。

In[15]: HachimanMath = HachimanSeries[0]
In[16]: 40 <= HachimanMath
Out[16]: False

ただし、HachimanMathの型は普通のintではなく、numpy.int64である。

In[17]: type(HachimanMath)
Out[17]: numpy.int64

配列[-1]も使える。
複数の変数を取り出す事も簡単だ。

In[18]: HachimanSeries[0:2]
Out[18]: 
[8, 38]

私の実行結果を鵜呑みのせず、自分自身の環境でサンプルコードを実行してきた読者なら、ここで私がとうとう馬脚を現して、うそを書いたことに気が付いたはずだ。

このコードHachimanSeries[0:2]pandas.core.series.Seriesという見るからにSeries型の実行結果を返してくる。

In[18]: HachimanSeries[0:2]
Out[18]: 
math         8
japanese    88
dtype: int64

In[19]: type(HachimanSeries[0:2])
Out[19]: pandas.core.series.Series

まとめると

  • 要素を単独で指定すると、numpy.int64というint型の様な実行結果が
  • 要素を範囲で指定するとpandas.core.series.SeriesというSeries型と言うべきものが返ってくる

ちょっと気持ち悪いと感じる人もいるかも知れないが、よくよく考えると

  • int->numpy.int64
  • list ->pandas.core.series.Series

という対応関係があるだけで、ごく普通の配列の操作と変わらない。
だからもちろん、単独の要素を持つSeries型は、配列から単独の配列を取り出すときと同様に取り出せる。

In[20]: HachimanSeries[1:1+1] 
Out[20]: 
japanese    88
dtype: int64

In[21]: type(HachimanSeries[1:1+1])
Out[21]: 
pandas.core.series.Series

要素を指定するには、辞書型のようにindex名で指定する方法もある。

In[22]: HachimanSeries["math"]
Out[22]: 8

ちなみに配列[::-1]を使うと、逆にした結果が返ってくる。

驚くべきことに、これはindex名を使って、範囲指定までできる。

In[23]: HachimanSeries["math":"english"]
Out[23]: 
math         8
japanese    88
english     38
dtype: int64

これは、普通の辞書はもちろん、collections.OrderedDictでもできないことであり、Seriesたんの高性能を示している。

なお、indexの名前にアクセスしたいときは、Series.indexを配列のように扱えばいい。

In[24]:HachimanSeries.index
Out[24]:Index(['math', 'japanese', 'english'], dtype='object')

In[25]: HachimanSeries.index[1]
Out[25]: 'japanese'

In[26]: HachimanSeries.index.[1:2]
Out[26]: Index(['japanese'], dtype='object')

ここまで、Seriesが普通の配列や辞書の様に要素を取り出せることを説明してきた。
####ほしい形のSeriesを手に入れる
Seriesのなかでデータのつまみ食いをしたい場合はどうすればいいだろうか?
つまり、mathjapaneseだけが欲しいとか、mathenglishだけが欲しいとか。
あるいは、mathが二か所に欲しいとか。
(今はそんな必要性を感じないか…)

mathjapaneseなら、HachimanSeries[0:2]でなんとかなる。しかし、mathenglishとなると、なかなか悩ましい。
そこで思いつく。

In[27]: HachimanSeries["math"]+HachimanSeries["english"]

これでどうだ!!

Out[27]: 46

現実は非情であるが、この出力はうなずける。そもそも、HachimanSeries["math"]の結果はnumpy.int64なのだから。

ならばと、

In[28]: HachimanSeries[0:0 + 1] + HachimanSeries[2:2 + 1]

を試してみる。

Out[28]: 
english   NaN
math       NaN
dtype: float64

見るからに産業廃棄物を吐いてきた。
これはおそらく、Seriesにおける足し算が、「同じindex同士を足す」ものだからであろう。
そして、共通しない要素に関しては、とりあえずNaNを埋めておくのだ。
現に

In[29]: HachimanSeries[0:0 + 2] + YukinoSeries[1:1 + 2]
Out[29]: 
english       NaN
japanese    188.0
math          NaN
dtype: float64

となる。

では、同じSeries内のmathenglishだけを贔屓するにはどうしたらいいだろうか。
答えは、二重に[]を書く、である。

In[30]: HachimanSeries[[0, 2]]
Out[30]:
math        8
english    38
dtype: int64

たぶん、この[[]]は二次配列の表記と関係ない。ただ単に[[]]という表記が使いたかっただけなのだと思われる。
HachimanSeries[(0,2)]は通らないため、イテレーター的な何かである必要はなかったのだろう。しかし、HachimanSeries[list((0,2))]は通るため、処理的には配列と同じであると考えられる。)

ひたすらに数学の得点を強調したければ、

In[31]: HachimanSeries[["math","math","math","math","math"]]
Out[31]: 
math    8
math    8
math    8
math    8
math    8
dtype: int64

とすればいい。(ここではindex名を直接指定した)
indexに関しても同様だ。

In [32]: HachimanSeries.index[[1,2]]
Out[32]: Index(['japanese', 'english'], dtype='object')

ここまで、[[]]を用いて、欲しいindexだけを抽出したSeriesを新しく作る方法を学んだ。
###Seriesの要素の書き換え
後からSeriesの中身やindex名が間違っていたことに気が付くかもしれない。
同じ名前で修正版Seriesを上書きする方法もあるが、実は、配列と同じように簡単に変えられる。

まずは一個だけ書き換えるコード。

In[33]:HachimanSeries[1]
Out[33]: 88

In[34]: HachimanSeries[1] = 98
 
In[35]: HachimanSeries[1]
Out[35]: 98 

次に指定した範囲を書き換える

In[36]: HachimanSeries
Out[36]: 
math         8
japanese    98
english     38
dtype: int64

In[37]: HachimanSeries[1:1+2] = [89,33]

In[38]: HachimanSeries
Out[38]: 
math         8
japanese    89
english     33
dtype: int64

ここで、左辺と右辺の個数があってないと怒られる。

In[39]: HachimanSeries[1:1+1] = [88,38]
-------------------
ValueError
(略)
ValueError: cannot set using a slice indexer with a different length than the value

ただし、同じ値に揃える事は出来る。

In[40]: HachimanSeries[0:0+3] = 0

In[41]: HachimanSeries
Out[40]: 
math        0
japanese    0
english     0
dtype: int64

最後に、indexの書き換え

In[42]: HachimanSeries.index[1] = "Japanese"
Out[42]: HachimanSeries
math        0
Japanese    0
english     0
dtype: int64

と実はこういかない。

TypeError: Index does not support mutable operations

とあるように、indexはイミュータブルであるようだ。(文字列で似たことをしても怒られる)

だから上書きするしかない。

In[43]: HachimanSeries.index = ["Math","Japanese","English"]

In[44]: HachimanSeries
Out[44]: 
Math        0
Japanese    0
English     0
dtype: int64

さて、復習がてらリセットしておこう。

In[45]: HachimanSeries[0:0+3] = [8,88,38]

In[46]: HachimanSeries.index = ["math", "japanese", "english"]
Out[46]: 
math         8
japanese    88
english     38
dtype: int64

以上、Seriesの基本的な操作である。
予想以上に長くなってしまったため、Dataframeについてや、Seriesのメソッドについては続く記事で記す。

124
92
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
124
92

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?