Lesson4

Pandasの使い方(データ解析)

1. 学習の目標

このレッスンでは Pandas というパッケージライブラリを紹介します。

pd_00.png

Pandasを使うことで、CSVファイルに保存されているデータをPythonのプログラム内に読み込んで、データ処理をすることができるようになります。また、通常の「テキストファイルを読み込む方法」よりも楽にデータを扱えます。

ここではCSVファイルを読み込み、作成された「DataFrame」という型のオブジェクトの簡単な操作ができるようになることが目標です。また、DataFrameという型はndarrayとは異なるものなので、それぞれに変換する方法についても学びます。

  • CSVファイルを読み込む
  • データを参照・表示する
  • DataFrameとndarrayを相互変換する

2. CSVファイルを読み込む

CSVファイルは、データをカンマ(,)で区切った形式として保存したテキストファイルです。ExcelやGoogleのスプレッドシートなどで「表」として開くことができます。異なる表計算ソフトの間でも同じように開けることが特長です。

このレッスンでは Machine Learning Repository で配布されている「bank.csv」のファイルを使います。同じファイルを用意しましたので、以下のリンクからダウンロードしてください。zip形式で圧縮したファイルですので、ダウンロードした後に解凍しましょう。解凍して出てきた bank.csv ファイルを、Cloud9の本レッスン用のノートブックがある場所と同じところにアップロードしてください(PCからアップするファイルやフォルダをAWS Cloud9のフォルダに向かってドラッグ&ドロップしましょう)。

bank.csv をコチラからダウンロード

このbank.zipは、銀行が持っている顧客情報のリスト(サンプル)で、以下の情報で構成されたデータが4500件程度、保存されています。

列名 概要
age 年齢
job 職業
marital 結婚した経験の有無
education 最終学歴
default 債務不履行かどうか
balance 口座残高
housing 住宅ローンの有無
loan パーソナルローンの有無
contact 連絡手段
day 最後に営業の連絡をした日にち(日)
month 最後に営業の連絡をした日にち(月)
duration 現在実施中のキャンペーンで最後に営業の連絡をした日からの経過日数
campaign 現在実施中のキャンペーンで営業の連絡をした回数
pdays 前回のキャンペーンで最後に営業の連絡をした日からの経過日数
previous 前回のキャンペーンで営業の連絡をした回数
poutcome 前回のキャンペーンでの結果
y 定期預金の契約の有無

bank.csv をJupyterLabのノートブックファイルが保管されているディレクトリへ格納してください。また、JupyterLabで新規ノートブックを作成し、 Lesson4 という名前にしてください。

まずはPandasをモジュールとしてインポートします。後ほどNumPyも使いますので、併せてインポートしておきます。

import pandas as pd
import numpy as np

では bank.csv を読み込みましょう。pd.read_csv() で読み込めます。引数にCSVファイルの場所(パス)を指定します。これだけです。bank.csv の1行目は列の見出しとなっていますが、それをそのまま「列名」として読み込んでくれるのも便利な点となっています。

bank_data = pd.read_csv("bank.csv")

これを実行することで、変数 bank_data には bank.csv に保存されていた銀行の顧客情報が格納されます。ここでひとつ注意したいのは、bank_data のデータ型です。調べてみると、以下のとおりです。

print(type(bank_data))

出力結果:

<class 'pandas.core.frame.DataFrame'>

DataFrame と表示されました。これはPandasにおける2次元配列のデータ型です。(1次元配列は Series というデータ型になります。)Python標準のリストや、NumPyのndarrayとは似たようなものですが異なるデータ型です。

3. データを参照・表示する

3.1 とりあえず表示する

DataFrameであることの利点のひとつは、JupyterLabでデータを表示しようとした場合、DataFrame型オブジェクトのメソッドに表示を任せると「綺麗な表」を出力してくれる点です。

print() は利用せず、JuputerLabに bank_data とだけ記述して実行してみてください。

bank_data

出力結果:

pd_01.png

このように、JupyterLabとPandasが連携して、きれいな表が出力されます。Python標準の print() でデータを表示しようとすると、単純にデータを文字で表示するだけとなり、このようにはなりません。

なお、bank_data には4500件のデータが入っているため、途中省略されているものの、非常に縦長の表示になりました。正常にCSVが読み込まれたかを確認したいだけなら head() というメソッドを利用してください。先頭から5件までしか表示しません。

bank_data.head()

出力結果:

pd_02.png

サンプルコードは省略しますが、逆に末尾のデータを表示する tail() も存在します。

3.2 スライス

位置の数値でスライスする

DataFrameでもリストやndarrayのようにスライスが可能です。配列名.iloc[行のスライス指定][列のスライス指定] もしくは 配列名.iloc[行のスライス指定, 列のスライス指定] のように記述します。

bank_data.iloc[1, 1]    # 1番目のみ

出力結果:

pd_03.png

bank_data.iloc[0:3, 0:3]    # 0番目から4番目まで

出力結果:

pd_04.png

bank_data.iloc[:11:2, :11:2]    # 先頭から12番目まで(増分2で)

出力結果:

pd_05.png

列名でスライスする

DataFrameでは 配列名.loc[] を使うことで列名によるデータの参照が可能です。1列だけ指定したい場合は列名の文字列のみを、複数の列を指定したい場合は列名の文字列をリストにしたものを loc[][] 内に記述してください。以下、一例です。

# bank_data.iloc[1, 1] と同じ出力結果になる
bank_data.loc[1, "job"]
# bank_data.iloc[0:3, 0:3] と同じ出力結果になる
bank_data.loc[0:2, ["age", "job", "marital"]]
# bank_data.iloc[:11:2, :11:2] と同じ出力結果になる
bank_data.loc[:10:2, ["age", "marital", "default", "housing", "contact", "month"]]

それぞれ、iloc の場合と同じ出力結果になることを確認してください。

loc の場合は iloc と異なり、行の指定でスライスを利用する場合、範囲が終わる場所は 終了位置 の場所も含まれています。 "終了位置 - 1" ではありません。上記のサンプルで iloc では bank_data.iloc[0:3, 0:3] としていますが loc では bank_data.loc[0:2, ["age", "job", "marital"]] です。少なくともカリキュラムで利用しているPandasのバージョンでは、このような仕様となっていますので注意しましょう。

3.3 特定の条件による抽出

ある列を指定し、その列の値が特定の条件を満たしている行のみを抽出する方法があります。

query()を使う方法

ひとつは query() という関数を使う方法です。 配列名.query(条件式) のように記述します。たとえば age 列の値が35以上のデータを抽出したい場合、以下のように記述します。

bank_data.query("age >= 35")

Out[]: 3049 rows × 17 columns(表は省略)

文字列型のデータを検索したい場合、その文字列を、条件式を囲むクォーテーションとは別のクォーテーションで囲まなければなりません。条件式全体にダブルクォーテーションを使った際は、探したい文字列値をシングルクォーテーションで囲ってください。以下は marital 列の値が「single」のデータを抽出したい場合の記述方法です。

bank_data.query("marital == 'single'")

Out[]: 1196 rows × 17 columns(表は省略)

query()を使わない方法

query() 関数は使わない方法もあります。

# ageが35以上のデータを抽出
bank_data[bank_data["age"] >= 35]
# maritalが「single」のデータを抽出
bank_data[bank_data["marital"] == "single"]

それぞれ query() を使う場合と結果が一致することを確認してください。

複数の条件を指定する方法

query() を使う場合と使わない場合の両方で、論理積・論理和による複数条件の指定が可能です。

query()を使う方法による複数条件の指定
# ageが35以上で、なおかつ、maritalが「single」のデータを抽出
bank_data.query("age >= 35 and marital == 'single'")
query()を使わない方法による複数条件の指定

こちらの場合、andor は利用できませんので、& および | を使いましょう。

# ageが35以上で、なおかつ、maritalが「single」のデータを抽出
bank_data[(bank_data["age"] >= 35) & (bank_data["marital"] == "single")]

どちらも出力内容は 437 rows × 17 columns で同一の表になっていることを確認してください。

4. DataFrameとndarrayを相互変換する

PandasにはPandasで、NumPyにはNumPyの便利な命令が、それぞれで用意されています。DataFrameで処理すべきかndarrayに変換するべきかは、処理内容によります。そこで、それぞれのデータ型への相互変換が必要です。

4.1 DataFrameからndarrayに変換する

DataFrameからndarrayへの変換は、DataFrameのオブジェクトが持つ values プロパティを参照すればOKです。

引き続き bank.csv を読み込んで作成した bank_data を利用します。

nd_bank_data = bank_data.values

print(type(nd_bank_data))
print(nd_bank_data)

出力結果:

<class 'numpy.ndarray'>
[[30 'unemployed' 'married' ... 0 'unknown' 'no']
 [33 'services' 'married' ... 4 'failure' 'no']
 [35 'management' 'single' ... 1 'failure' 'no']
 ...
 [57 'technician' 'married' ... 0 'unknown' 'no']
 [28 'blue-collar' 'married' ... 3 'other' 'no']
 [44 'entrepreneur' 'single' ... 7 'other' 'no']]

なお values プロパティには列見出しの情報は入っていません。列見出しが欲しいときは 配列名.columns.values という指定をしてください。列見出しがndarrayの形式で取得できます。

nd_bank_columns = bank_data.columns.values

print(type(nd_bank_columns))
print(nd_bank_columns)

出力結果:

<class 'numpy.ndarray'>
['age' 'job' 'marital' 'education' 'default' 'balance' 'housing' 'loan'
 'contact' 'day' 'month' 'duration' 'campaign' 'pdays' 'previous'
 'poutcome' 'y']

4.2 ndarrayからDataFrameに変換する

逆にndarrayからDataFrameのオブジェクトを作るには pd.DataFrame() を実行します。pd.DataFrame()datacolumns というキーワード引数を持っています。data にはデータの値そのものを、また colums には列見出しの情報を ndarray形式で指定してください。

re_bank_data = pd.DataFrame(data = nd_bank_data, columns = nd_bank_columns)

print(type(re_bank_data))
re_bank_data.head()

出力結果:

pd_06.png

5. まとめ

このレッスンではPandasの使い方を学びました。CSVファイルからデータを読み込むことが簡単にできるライブラリです。

次のレッスンでは、画像ファイルを読み込むことができるライブラリを紹介します。

Lesson5 Pillowの使い方(画像加工)へ進む
Copyright 2020 SAKURA Internet Inc. All rights reserved