Blow Up by Black Swan

Python-pandasモジュールの基本的な使い方1: 10 minutes to pandas

現在、チャートを作ろうとしている最中ですので、今回pandasモジュールの使い方を学んでみました。pandasの公式サイトはこちらですが、このサイトのチュートリアルではなく、『10 minutes to pandas』をやったので、この内容をまとめた記事を書こうと思います。

pandasのバージョンは、0.23.3です。

10 minutesと書いていますが、10分で到底終わるものではなく、実際に手を動かしながら学習した結果5時間以上かかりました。量が多かったので2記事に分けています。分量も多く、公式ドキュメントも英語ですので、時間がない方や英語が苦手な方の参考にされば幸いです。

1. pandasとは?

公式サイトでは、pandasについて、以下のように説明されています。

「pandas is a Python package providing fast, flexible, and expressive data structures designed to make working with “relational” or “labeled” data both easy and intuitive. It aims to be the fundamental high-level building block for doing practical, real world data analysis in Python. Additionally, it has the broader goal of becoming the most powerful and flexible open source data analysis / manipulation tool available in any language. It is already well on its way toward this goal.」

要するに、直感的にデータを扱えるようにしたパッケージで、高速、柔軟性、表現に富むデータ構造を表せるものだということです。データの扱いに重点を置いたパッケージだとのことです。

2. pandasのインストールとインポート

pandasは、サードパーティーモジュールになるため、インストールする必要があります。今回の学習のベースとなる「10 minutes to pandas」では、numpyとmatplotlibも必要としていますので、それらのパッケージをpipを使用してインストールします。

pip3 install pandas
pip3 install numpy
pip3 install matplotlib

また、モジュールは以下のように短縮した名称を指定してインポートしています。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

3. 10 minutes to pandas

ここからは、10 minutes to pandasを私なりにまとめた内容です。章ごとに、利用したメソッド等をまとめていますが、DataFrameとSeriesではともにメソッド等がかなり重複しているようで、DataFrameで使えるメソッドがSeriesオブジェクトでも利用できる場合もありますので、そこは適宜公式ドキュメント等を確認いただければと思います。

(1) オブジェクトの生成

まずは、pandasで使うオブジェクトの作成方法です。pandasの代表的なオブジェクトは以下の2つです。

  • Seriesオブジェクト・・・一次元配列を表す
  • DataFrameオブジェクト・・・二次元配列を表す

配列は表のようなものでコードの戻り値をみれば、すぐにわかると思います。また、Panelオブジェクトという三次元配列を扱うオブジェクトも存在しますが、10 minutes to pandasでは扱われていません。Seriesオブジェクトの生成からです。

#Seriesオブジェクト
s = pd.Series([1,3,5,np.nan,6,8])  #np.nanはリストの欠損値を指す
s

戻り値

01.0
13.0
25.0
3NaN
46.0
58.0

次はDataFrameオブジェクトの生成です。

#DataFrameオブジェクト
#datetimeのrowとラベルづけされたcolumnを持つデータ構造

dates = pd.date_range('20130101', periods=6)  #date_range()…固定されたインデックスを返す
#datesの格納内容 -> DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'], dtype='datetime64[ns]', freq='D')

df =pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
#np.random.randn()…標準正規分布に沿ってランダムな値を生成

df

戻り値

 ABCD
2013-01-010.6402450.2218880.161165-0.158784
2013-01-02-0.842354-1.756285-0.629484-1.589416
2013-01-03-0.298022-0.768641-0.613439-0.665621
2013-01-04-1.9841550.740455-0.928366-0.510639
2013-01-05-1.918457-0.258365-1.4690692.910253
2013-01-060.163206-0.2022590.1198200.606145

DataFrameオブジェクトは、pythonのdict型を使用しても、作成できます。

#DataFrameオブジェクト(Series型にも変換できるdict型を使った場合)
df2 = pd.DataFrame({'A' : 1.,
                    'B' : pd.Timestamp('20130102'),
#pandas.Timestamp()…pandas用のタイムスタンンプ生成
                    'C' : pd.Series(1,index=list(range(4)),dtype='float32'),
                    'D' : np.array([3] 4,dtype='int32'),  #numpy.array()…一次元配列の作成
                    'E' : pd.Categorical(["test","train","test","train"]),
#pandas.Categorical()…変数を表すメソッド
                    'F' : 'foo' })

df2

戻り値

 ABCDEF
01.02013-01-021.03testfoo
11.02013-01-021.03trainfoo
21.02013-01-021.03testfoo
31.02013-01-021.03trainfoo

ここで使用したメソッド等は以下になります。

  • Series()…一次元配列のSeriesオブジェクトを生成。
  • date_range()…固定されたデートタイムインデックスを返すメソッド。return -> DatetimeIndex型
    • 引数:start=開始日(str型 or datetime型), end=終了日(str型 or datetime型), periods=期間(int型), frequency=時間の頻度
  • DataFrame()…二次元配列のDataFrameオブジェクトを生成。
  • randam.randn()…標準正規分布に沿って乱数を生成する。 -> ndarray型
    • 引数:データ配列の次元に合わせて指定する(row, column…)

(2). データを見る

次は、DataFrameやSeriesのデータを見る方法です。

・head()メソッド

df.head(2)  #DataFrame.head(n)…最初からn列目までのデータを表示

戻り値

 ABCD
2013-01-010.6402450.2218880.161165-0.158784
2013-01-02-0.842354-1.756285-0.629484-1.589416

・tail()メソッド

df.tail(3)  #DataFrame.tail(n)…最後からn列目までのデータを表示

戻り値

 ABCD
2013-01-04-1.9841550.740455-0.928366-0.510639
2013-01-05-1.918457-0.258365-1.4690692.910253
2013-01-060.163206-0.2022590.1198200.606145

headメソッドは上からtailメソッドは下から、引数に指定した個数のデータにアクセスします。

・index属性

df.index  #DataFrame.index…インデックス値を表示

戻り値

DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
               '2013-01-05', '2013-01-06'],
              dtype='datetime64[ns]', freq='D')

・columns属性

df.columns  #DataFrame.columns…カラム値を表示

戻り値

Index(['A', 'B', 'C', 'D'], dtype='object')

・values属性

df.values  #DataFrame.values…バリューをリスト(カラム単位)で返す

戻り値

array([[ 0.64024466,  0.22188846,  0.1611652 , -0.15878385],
       [-0.84235402, -1.75628475, -0.62948437, -1.58941564],
       [-0.29802182, -0.76864116, -0.61343897, -0.66562134],
       [-1.98415456,  0.74045532, -0.92836589, -0.51063921],
       [-1.91845718, -0.25836465, -1.46906898,  2.91025334],
       [ 0.1632055 , -0.20225916,  0.11981968,  0.60614479]])

index、columns、valuesは、それぞれのデータのインデックス、カラム、バリューにアクセスする属性です。

・describe()メソッド

df.describe()  #データの統計サマリーを返す

戻り値

 ABCD
count6.0000006.0000006.0000006.000000
mean-0.706590-0.337201-0.5598960.098656
std1.0822810.8600330.6248231.551377
min-1.984155-1.756285-1.469069-1.589416
25%-1.649431-0.641072-0.853646-0.626876
50%-0.570188-0.230312-0.621462-0.334712
75%0.0478990.115852-0.0634950.414913
max0.6402450.7404550.1611652.910253

describeメソッドで、統計データを返してくれます。

・T属性(transpose()メソッド)

df.T  #データとカラムを入れ替える

戻り値

 2013-01-01 00:00:002013-01-02 00:00:002013-01-03 00:00:002013-01-04 00:00:002013-01-05 00:00:002013-01-06 00:00:00
A0.640245-0.842354-0.298022-1.984155-1.9184570.163206
B0.221888-1.756285-0.7686410.740455-0.258365-0.202259
C0.161165-0.629484-0.613439-0.928366-1.4690690.119820
D-0.158784-1.589416-0.665621-0.5106392.9102530.606145

T属性は、transpose(日本語訳:転置)の略です。インデックスとカラムを入れ替えます。

この属性値は、transposeメソッドを使用することもできます。
(例:df.transpose() -> 上記と同一の結果が得られる)

・sort_index()メソッド

df.sort_index(axis=1, ascending=False)  #インデックス値でソート

戻り値

 DCBA
2013-01-01-0.1587840.1611650.2218880.640245
2013-01-02-1.589416-0.629484-1.756285-0.842354
2013-01-03-0.665621-0.613439-0.768641-0.298022
2013-01-04-0.510639-0.9283660.740455-1.984155
2013-01-052.910253-1.469069-0.258365-1.918457
2013-01-060.6061450.119820-0.2022590.163206

このコードでは、カラムを降順でソートしています。

・sort_values()メソッド

df.sort_values(by="B")  #バリュー値でソート

戻り値

 ABCD
2013-01-02-0.842354-1.756285-0.629484-1.589416
2013-01-03-0.298022-0.768641-0.613439-0.665621
2013-01-05-1.918457-0.258365-1.4690692.910253
2013-01-060.163206-0.2022590.1198200.606145
2013-01-010.6402450.2218880.161165-0.158784
2013-01-04-1.9841550.740455-0.928366-0.510639

ここでは、カラムB(B行)のデータを昇順でソートしています。

ここで利用したメソッド等は以下になります。

  • DataFrame.head(n)…最初のn列目までの情報を返す(デフォルトは5)
  • DataFrame.tail(n)…最後からのn列目までの情報を返す(デフォルトは5)
  • DataFrame.index…インデックスを返す属性
  • DataFrame.columns…カラムを返す属性
  • DataFrame.values…DataFrameのバリューをカラム単位で返す属性
  • DataFrame.describe()…データの統計サマリーを返す
  • DataFrame.T…rowとcolumnsを転置して返す属性
  • DataFrame.sort_index()…インデックス値でソート
    • 引数: axis=軸(0がrow、1がカラム), ascending=昇順か降順か
  • DataFrame.sort_values()…バリュー値でソート
    • 引数: by=基準点

(3). セレクション

次も前の章と似ていますが、選択したデータの取得についてです。

(3)-1. データの取得

Pnadasのオブジェクトでは、dict型のようにデータにアクセスすることもできます。

df['A']  #Aの取得。df.Aでも取得可能

戻り値

2013-01-01    0.640245
2013-01-02   -0.842354
2013-01-03   -0.298022
2013-01-04   -1.984155
2013-01-05   -1.918457
2013-01-06    0.163206
Freq: D, Name: A, dtype: float64

スライスを用いたアクセスも可能です。

df[1:4]  #スライスを用いた値の取得。df.head(),def.tail(n)と一部類似
#df["20130102":"20130104"]でも可

戻り値

 ABCD
2013-01-02-0.842354-1.756285-0.629484-1.589416
2013-01-03-0.298022-0.768641-0.613439-0.665621
2013-01-04-1.9841550.740455-0.928366-0.510639

(3)-2. ラベルによる取得

インデックスやカラムのラベルからデータを取得することもできます。

・loc属性

df.loc[dates[0]]  #該当するインデックスラベルのカラムーバリューを取得。df.loc["20130101”]と同義

戻り値

A    0.640245
B    0.221888
C    0.161165
D   -0.158784
Name: 2013-01-01 00:00:00, dtype: float64
df.loc[:,['A','B']]  #df.loc[:,'A':'B']と同義。注意点[コロンが必要]
#df.loc['20130101':'20130106',['A','B']]といった設定もできる

ここでの注意点は、インデックスラベルを全指定するためには、カンマの前にコロンを記載する必要があるところです。

戻り値

 AB
2013-01-010.6402450.221888
2013-01-02-0.842354-1.756285
2013-01-03-0.298022-0.768641
2013-01-04-1.9841550.740455
2013-01-05-1.918457-0.258365
2013-01-060.163206-0.202259

・at属性

df.at[dates[0],'A']  #単一のバリューを取得する場合。df.at["20130101","A"]と同義

戻り値

0.6402446576728557

(3)-3. ポジション(位置による取得)

Int型で位置を指定してデータを取得することもできます。

・iloc属性

df.iloc[3]  #インデックスの順番に沿ったint型で取得するデータを指定できる。df.loc["20130104"]と同じ

戻り値

A   -1.984155
B    0.740455
C   -0.928366
D   -0.510639
Name: 2013-01-04 00:00:00, dtype: float64

一の範囲からデータを取得することも可能です。

df.iloc[3:5,0:2]

戻り値

 AB
2013-01-04-1.9841550.740455
2013-01-05-1.918457-0.258365

・iat属性

df.iat[1,1]  #df.atのint版

戻り値

-1.7562847477402643

(3)-4. bool式

bool式(True or False)でのデータ取得の方法です。

df[df.A > 0]  #条件を満たすバリューを返す

カラムA(A行)のデータで値が0を超えるバリューを取得する式です。

戻り値

 ABCD
2013-01-010.6402450.2218880.161165-0.158784
2013-01-060.163206-0.2022590.1198200.606145
df[df > 0]

バリューが0より大きいものを取得します。

戻り値

 ABCD
2013-01-010.6402450.2218880.161165NaN
2013-01-02NaNNaNNaNNaN
2013-01-03NaNNaNNaNNaN
2013-01-04NaN0.740455NaNNaN
2013-01-05NaNNaNNaN2.910253
2013-01-060.163206NaN0.1198200.606145

条件に合致しないものは、NaN表記となっています。

df2 = df.copy()  #DataFrameオブジェクトのコピーを作成
df2['E'] = ['one', 'one','two','three','four','three']
df2

ここでは、Eの値を順に変えています。

戻り値

 ABCDE
2013-01-010.6402450.2218880.161165-0.158784one
2013-01-02-0.842354-1.756285-0.629484-1.589416one
2013-01-03-0.298022-0.768641-0.613439-0.665621two
2013-01-04-1.9841550.740455-0.928366-0.510639three
2013-01-05-1.918457-0.258365-1.4690692.910253four
2013-01-060.163206-0.2022590.1198200.606145three

(3)-5. セッティング

次の行も新たな値をセットしています。

df['F'] = pd.Series([1,2,3,4,5,6], index=pd.date_range('20130102', periods=6))  #F行の指定
df.at[dates[0],'A'] = 0  #df["20130101","A"]のバリュー変更
df.iat[0,1] = 0  #df["20130101","B"]のバリュー変更
df.loc[:,'D'] = np.array([5] len(df))  #D行のバリュー変更
df

戻り値

 ABCDF
2013-01-010.0000000.0000000.1611655NaN
2013-01-02-0.842354-1.756285-0.62948451.0
2013-01-03-0.298022-0.768641-0.61343952.0
2013-01-04-1.9841550.740455-0.92836653.0
2013-01-05-1.918457-0.258365-1.46906954.0
2013-01-060.163206-0.2022590.11982055.0

カラムA,B,Dの値がそれぞれ変わっていることがわかります。

(3)-6. 欠損値

Pandasでは、欠損値にはnp.nanが使用されます。

df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])  #インデックスの再割り当て
df1.loc[dates[0]:dates[1],'E'] = 1  #E行の割り当て
df1
#下の表で欠損値がNaNで表示されているのがわかる

戻り値

 ABCDFE
2013-01-010.0000000.0000000.1611655NaN1.0
2013-01-02-0.842354-1.756285-0.62948451.01.0
2013-01-03-0.298022-0.768641-0.61343952.0NaN
2013-01-04-1.9841550.740455-0.92836653.0NaN

・dorpna()メソッド
下のコードでは欠損値を除外しています。

df1.dropna(how='any')  #欠損値を除外

戻り値

 ABCDFE
2013-01-02-0.842354-1.756285-0.62948451.01.0

・fillna()メソッド
欠損値に指定したデータを入力します。

df1.fillna(value=5)  #欠損値を補充

戻り値

 ABCDFE
2013-01-010.0000000.0000000.16116555.01.0
2013-01-02-0.842354-1.756285-0.62948451.01.0
2013-01-03-0.298022-0.768641-0.61343952.05.0
2013-01-04-1.9841550.740455-0.92836653.05.0

・isna()メソッド

pd.isna(df1)  #欠損値の部分をFalse、欠損値でない部分をTrueで表し、欠損値を見つけ出すメソッド

戻り値

 ABCDFE
2013-01-01FalseFalseFalseFalseTrueFalse
2013-01-02FalseFalseFalseFalseFalseFalse
2013-01-03FalseFalseFalseFalseFalseTrue
2013-01-04FalseFalseFalseFalseFalseTrue

ここで登場したメソッド等は以下になります。

  • DataFrame.loc…ラベルに沿ったrowやcolumnにアクセスする属性
    • 設定の仕方: DataFrame.loc[row:column]rowを指定しない場合はコロン(:)を入力
  • DataFrame.iloc…int型で取得するあ隊を指定できる属性。設定形式はlocと同じ
  • DataFrame.at…単一の値を取得できる属性。設定形式はlocと同じ
  • DataFrame.iat…DataFrame.atのint版
  • DataFrame.copy()…DataFrameオブジェクトのコピーを作成
  • DataFrame.reindex()…インデックスの再割り当て
  • DataFrame.dropna()…欠損値を除外するメソッド
    • 引数:how=”any”or”all”(any->1つでも欠損値があればそのrowかcolumnを除外。allは全て欠損値の場合)
  • DataFrame.fillna()…欠損値を補充するメソッド
  • DataFrame.isna()…そのマスが欠損地下道かをbool式(True or False)で表すメソッド
    • 引数: value=補充する値
  • array()…一次元配列を作るメソッド。 -> ndarray型

(4). オペレーション

ここで出てくるのは、データに対して様々な処理ができるメソッドなどです。

(4)-1. 統計

統計データ関連です。

・mean()メソッド

df.mean()  #平均を返す

戻り値

A   -0.813297
B   -0.374182
C   -0.559896
D    5.000000
F    3.000000
dtype: float64

カラムを軸とした場合は以下になります。

df.mean(1)  #カラムが軸

戻り値

2013-01-01    1.290291
2013-01-02    0.554375
2013-01-03    1.063980
2013-01-04    1.165587
2013-01-05    1.070822
2013-01-06    2.016153
Freq: D, dtype: float64
s = pd.Series([1,3,5,np.nan,6,8], index=dates).shift(2)  #n個動かすメソッド
s

戻り値

2013-01-01    NaN
2013-01-02    NaN
2013-01-03    1.0
2013-01-04    3.0
2013-01-05    5.0
2013-01-06    NaN
Freq: D, dtype: float64

・sub()メソッド

df.sub(s, axis='index')  #他の要素とデータフレームとの減算(df-s)

戻り値

 ABCDF
2013-01-01NaNNaNNaNNaNNaN
2013-01-02NaNNaNNaNNaNNaN
2013-01-03-1.298022-1.768641-1.6134394.01.0
2013-01-04-4.984155-2.259545-3.9283662.00.0
2013-01-05-6.918457-5.258365-6.4690690.0-1.0
2013-01-06NaNNaNNaNNaNNaN

(4)-2. 適用

データの他の処理を適用させることもできます。 

・apply()メソッド

df.apply(np.cumsum)  #データに関数を通すメソッド(np.cumsum()は累積和を返すメソッド)

rowの上から順番に累積和を計算しています。

戻り値

 ABCDF
2013-01-010.0000000.0000000.1611655NaN
2013-01-02-0.842354-1.756285-0.468319101.0
2013-01-03-1.140376-2.524926-1.081758153.0
2013-01-04-3.124530-1.784471-2.010124206.0
2013-01-05-5.042988-2.042835-3.4791932510.0
2013-01-06-4.879782-2.245094-3.3593733015.0
df.apply(lambda x: x.max() - x.min())  #最大値ー最小値

各カラムの最大値から最小値を引いた値を返しています。

最小値がマイナスの場合、最大値と最小値の絶対値の和になる点が少し混乱しやすいと思います。

戻り値

A    2.147360
B    2.496740
C    1.630234
D    0.000000
F    4.000000
dtype: float64

(4)-3. ヒストグラム

度数分布を求める場合です。

・value_counts()メソッド

s = pd.Series(np.random.randint(0, 7, size=10)) #np.random.randint()…一様分布のランダムな整数を返す
s

戻り値

0    3
1    4
2    1
3    3
4    4
5    0
6    5
7    0
8    6
9    2
dtype: int64
s.value_counts() #それぞれの出目ごとにでた個数を返す
s.value_counts() #それぞれの出目ごとにでた個数を返す

ここでは出た目の個数を返しています。

戻り値

4    2
3    2
0    2
6    1
5    1
2    1
1    1
dtype: int64

(4)-4. 文字列メソッド

pandasでは文字列を取り扱うメソッド,strメソッドを持っています。 

・str.lower()メソッド

s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
s.str.lower()  #小文字に統一するメソッド

戻り値

0       a
1       b
2       c
3    aaba
4    baca
5     NaN
6    caba
7     dog
8     cat
dtype: object

ここで登場したメソッド等は以下になります。

  • DataFrame.mean()…平均を返すメソッド
  • Series.shift(n)…n個データを移動させるメソッド
  • DataFrame.sub(s)…データフレームと他の要素xとの減算(df-x)
  • DataFrame.apply()…DataFrameに関数を適用するメソッド。軸に添いSeriesと皆して適用する
  • Series.value_counts()…度数分布を返すメソッド
  • Series.str.lower() …文字列を小文字に変換するメソッド

分量があまりにも多くなってしまったため、続きは以下の記事で読めます。

参考になりましたら、幸いです。