2017年12月24日日曜日

[Python] Numpy と Pandas の基本

NumpyやPandasはデータを読み込んだ利,整形したり,集計したりするのに便利なパッケージです.これらの外部パッケージを読み込むと,便利な関数やクラスを流用することができます.
Numpyはアレイ(正確にはndarray)というデータを保持するクラスを主に使います.また,行列演算にも強いパッケージです.
Pandasはデータフレーム(DataFrame)というデータ管理のためのとても強力なクラスを持っています.

まずはパッケージの読み込みを行います.
>>> import numpy as np
>>> import pandas as pd
これで,NumpyとPandasの二つのパッケージを読み込むことができました.また,Numpyの機能を使う場合は np.クラス名,pd.クラス名と記述します.

複数のデータをまとめたものをリスト(list)と呼びます.リストはNumpyもPandasも必要ない,Python標準のデータの形式です.リストは半角の角括弧で複数のデータを囲むことによって作ります.
>>> sample_list = [1, 2, 3, 4, 5]
>>> sample_list
[1, 2, 3, 4, 5]
リストの中身を表示するには,上記の2行目のように変数名だけを記述します.なお,以下のようにprint関数を使っても結果は同じです.

>>> print(sample_list)

[1, 2, 3, 4, 5]


リストを用いてアレイを作ります.Numpyの中で作成されたクラスを用いるので,np.array と記述します.
>>> sample_array = np.array([1, 2, 3, 4, 5])
>>> sample_array
array([1, 2, 3, 4, 5])

アレイに対する演算は,アレイの中身のデータ全てに対して一律に適用される.例えば足し算ならば以下のようになる.
>>> sample_array + 2
array([3, 4, 5, 6, 7])

掛け算も同様です.
>>> sample_array * 2
array([ 2,  4,  6,  8, 10])

同一のアレイには,同一のデータの型しか入れることができません.仮に,数値型と文字列型を同時に入れようとすると,全てが文字列型として扱われてしまいます.
>>> np.array([1, 2, "A"])
array(['1', '2', 'A'], dtype='<U21')

2次元の配列を作ることもできます.2次元配列を作るときには,リストを入れ子にしたものを引数に指定します.
>>> sample_array_2 = np.array(
...     [[1, 2, 3, 4, 5],
...      [6, 7, 8, 9, 10]])
>>> sample_array_2
array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10]])

行数や列数は以下のようにして取得できます.
>>> sample_array_2.shape
(2, 5)
2行5列と返ってきています.

アレイを作成するには,上記のように引数を直接指定する方法以外にも様々なものがあります.まずは,等差数列の例を示します.

まずは,{1, 2, 3, 4, 5}というスタートが1で差分が1の等差数列を使います.等差数列を作るには np.arange 関数を用います.引数には開始位置(start),終了位置(stop),差分(step)を指定します.終了位置は,この位置に来たら終了するという意味になるので,stopの位置はアレイの要素には含まれません.
>>> np.arange(start = 1, stop = 6, step = 1)
array([1, 2, 3, 4, 5])

続いて,0.1から始まり0.8で終わる,差分0.2の等差数列を作成します.

>>> np.arange(start = 0.1, stop = 0.8, step = 0.2)

array([0.1, 0.3, 0.5, 0.7])


なお,start =, stop =, step =という記述は省略することができます.
>>> np.arange(0.1, 0.8, 0.2)
array([0.1, 0.3, 0.5, 0.7])

同じ値を沢山格納したアレイを作る場合には np.tile 関数を使います.例えば,Aというアルファベットを5つ格納した配列を作成するには以下のようにします.
>>> np.tile("A", 5)
array(['A', 'A', 'A', 'A', 'A'], dtype='<U1')

数値を格納することも可能です.
>>> np.tile(0, 4)
array([0, 0, 0, 0])

全ての値が零であるアレイは np.zeros 関数を使うとより簡単に作成できます.引数にはアレイの要素数を指定します.
>>> np.zeros(5)
array([0., 0., 0., 0., 0.])

2次元のアレイにするときには,要素数を [行数, 列数] の潤に指定します.

>>> np.zeros([2, 3])

array([[0., 0., 0.],

       [0., 0., 0.]])

1で埋めることも可能です.

>>> np.ones([3, 3])

array([[1., 1., 1.],

       [1., 1., 1.],
       [1., 1., 1.]])

Numpyのアレイやリストはスライシングという技法を使って簡単にデータの抽出をすることができます.以下に例を示します.

まずは,1行のアレイを作ります.
>>> d1_array = np.array([1, 2, 3, 4, 5])
>>> d1_array
array([1, 2, 3, 4, 5])

データの抽出を行うには,角括弧を用います.例えば,最初の要素を取得する場合には d1_array[0] とします.Pythonではインデックスが0から始まることに注意が必要です.
>>> d1_array[0]
1
上記の例では,0番目の要素を抽出しています.

範囲を指定して抽出する場合にはコロン(:)を使います.例えば[1; 3]と指定すると,インデックスが1番と2版のものが取得されます.3の一つ前までの抽出になることに注意が必要です.
>>> d1_array[1:3]
array([2, 3])

2行以上のアレイにおいても角括弧を使うことで簡単にデータを抽出できます.以下の例では2次元のアレイを作って要素を抽出しています.
>>> d2_array = np.array(
...     [[1, 2, 3, 4, 5],
...     [6, 7, 8, 9, 10]])
>>> d2_array
array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10]])
行インデックス,列インデックスの順番に番号を指定することで要素を抽出します.
インデックスは0始まりなので,[0, 3]は1行目4列目となることに注意が必要です.
>>> d2_array[0, 3]
4
コロン記号を使うことで複数の要素を抽出できます.

続いて,Pandasのデータフレームを使用してみます.
データフレームでは,列の名称と列に格納するデータを 'col1': sample_array のようにして指定します.
アレイと異なり,データフレームは列が異なれば数値型と文字列型を混在させることが可能です.
>>> sample_df = pd.DataFrame({
...     'col1' : sample_array,
...     'col2' : sample_array * 2, 
...     'col3' : ["A", "B", "C", "D", "E"]
... })
>>> print(sample_df)
   col1  col2 col3
0     1     2    A
1     2     4    B
2     3     6    C
3     4     8    D
4     5    10    E

上記の例ではデータフレームを表示させるために print関数を用いていますが,sample_df としても同じ結果が得られます(ただし,Jupyter Notebookでは見た目が変わります).
>>> sample_df
   col1  col2 col3
0     1     2    A
1     2     4    B
2     3     6    C
3     4     8    D
4     5    10    E

データフレームは,上記のように自分で作成する場合もありますが,既存の外部データを読み込む際にも用いられます.
例えば,データが .csv ファイルで保存されていて,作業中のディレクトリと同じ場所に格納されているときには,以下のようにしてデータを読み込みます.
データを格納する変数名 = pd.read_csv("ファイル名")
今回は,2-4-1-sample_data.csv *というファイルを読み込んでみます.読み込まれたデータはデータフレームとなっています.
>>> file_data = pd.read_csv("2-4-1-sample_data.csv")
>>> print(file_data)
   col1 col2
0     1    A
1     2    A
2     3    B
3     4    B
4     5    C
5     6    C

作成されたデータフレームを結合して,新たなデータフレームを作ることも可能です.
まずは,データフレームを2つ作ります.
>>> df_1 = pd.DataFrame({
...     'col1' : np.array([1, 2, 3]),
...     'col2' : np.array(["A", "B", "C"])
... })
>>> df_2 = pd.DataFrame({
...     'col1' : np.array([4, 5, 6]), 
...     'col2' : np.array(["D", "E", "F"])
... })
>>> df_1
   col1 col2
0     1    A
1     2    B
2     3    C
>>> df_2
   col1 col2
0     4    D
1     5    E
2     6    F

これらのデータフレームを縦方向に繋げるには,pd.concat関数を用います.
>>> print(pd.concat([df_1, df_2]))
   col1 col2
0     1    A
1     2    B
2     3    C
0     4    D
1     5    E
2     6    F
3行2列のデータフレームを縦方向に二つ繋げるので,結果は6行2列のデータフレームになります.

>>> pd.concat([df_1, df_2]).shape

(6, 2)


続いて,横方向に結合させます.横方向に結合するには,axis = 1 という引数を追加します.
>>> print(pd.concat([df_1, df_2], axis = 1))
   col1 col2  col1 col2
0     1    A     4    D
1     2    B     5    E
2     3    C     6    F
3行2列のデータフレームを横方向に二つ繋げるので,結果は3行4列のデータフレームになります.

>>> pd.concat([df_1, df_2], axis = 1).shape

(3, 4)


pd.concat 関数は他にも様々な結合をさせることが可能です.データベースの操作に使うSQLがわかれば,より複雑な挙動をさせることも可能です.

データフレームには,データの抽出などの操作を行う関数が豊富にあります.以下にいくつか例を示します.
例には,以前に作成した sample_df(5行3列のデータ)を用います.
>>> sample_df
   col1  col2 col3
0     1     2    A
1     2     4    B
2     3     6    C
3     4     8    D
4     5    10    E

列名を指定して取得する場合はドット記号(.)を用います.
>>> print(sample_df.col2)
0     2
1     4
2     6
3     8
4    10
Name: col2, dtype: int64

以下のように角括弧を使う方法もあります.
>>> print(sample_df["col2"])
0     2
1     4
2     6
3     8
4    10
Name: col2, dtype: int64

複数列を抽出することも可能です.複数列を抽出するには,列名を指定する角括弧の中にリスト形式で列名を複数指定します.
>>> print(sample_df[["col2", "col3"]])
   col2 col3
0     2    A
1     4    B
2     6    C
3     8    D
4    10    E

抽出ではなく,削除することも可能です.
>>> print(sample_df.drop("col1", axis = 1))
   col2 col3
0     2    A
1     4    B
2     6    C
3     8    D
4    10    E
削除するときには,.drop 関数を用いて,丸括弧になることに注意が必要です.

sample_df の最初の指定行を取得するには,head 関数を用います.
>>> print(sample_df.head(n = 3))
   col1  col2 col3
0     1     2    A
1     2     4    B
2     3     6    C
上記の例のように .head( n = 3)というように,取得する行を指定します.指定した数字(例では3)の前の行までが取得されます.

さらに,query 関数を使って特定の行のみを取得することも可能です.
>>> print(sample_df.query('index == 0'))
   col1  col2 col3
0     1     2    A
上記の例では,index == 0 ということで1行目の身を取得しています.

query関数を用いると,様々な条件でデータを取得することが可能です.
以下は,col3 という列の値がAである行のみを抽出するには以下のようにします.
>>> print(sample_df.query('col3 == "A"'))
   col1  col2 col3
0     1     2    A

複数の条件を指定することも可能です.
query('col3 == "A" | col3 == "D"') と指定すると,col3 がAまたはD であるという条件で抽出できる.または( | )の条件はOR条件とも呼ばれます.
>>> print(sample_df.query('col3 == "A" | col3 == "D"'))
   col1  col2 col3
0     1     2    A
3     4     8    D

query('col3 == "A" & col3 == "3"') と指定すると,col3がAであり,かつ,col1が3であるという条件で抽出することになります.かつ(&)の条件はAND条件とも呼ばれます.
>>> print(sample_df.query('col3 == "A" & col1 == "3"'))
Empty DataFrame
Columns: [col1, col2, col3]
Index: []
今回の例では,sample_df の中に条件を満たす行がないので,上記のように返ってきます.

行と列を指定することもできます.
>>> print(sample_df.query('col3 == "A"') [["col2", "col3"]])
   col2 col3
0     2    A

pandasデータフレームにおいて1列だけを抽出したものは,シリーズと呼ばれる別のデータの型に変わります.
まずは,sample_df のクラス名がDataFrameになっていることを確認します.
>>> type(sample_df)
<class 'pandas.core.frame.DataFrame'>

続いて,1列だけ抽出した結果のクラス名を調べます.
>>> type(sample_df.col1)
<class 'pandas.core.series.Series'>
DataFrameではなく,Seriesと表示されていることがわかります.
シリーズは,Numpyアレイとほぼ同様に扱うことが可能です(シリーズを自分で作成することは少ないのですが,1列だけを抽出すると,自動的にシリーズ形式になるので,分析を行う際にしばしば登場します).

シリーズはアレイとぼぼ同様に扱えるものの,アレイの方が扱いやすい場合もあります.シリーズをアレイに変換する場合には,np.array の引数にシリーズ型の変数を入れます.
>>> type(np.array(sample_df.col1))
<class 'numpy.ndarray'>

シリーズに対して,.value と付けてもアレイとして抽出することが可能です.
>>> type(sample_df.values)
<class 'numpy.ndarray'>

この投稿をJupyter Notebookで実行した結果はGiHubで見ることができます.

2-4-1-sample_data.csvの中身
col1,col2
1, A
2, A
3, B
4, B
5, C
6, C

0 件のコメント :

コメントを投稿