paiza開発日誌

IT/Webエンジニア向け総合求人・学習サービス「paiza」(https://paiza.jp ギノ株式会社)の開発者が開発の事、プログラミングネタ、ITエンジニアの転職などについて書いています。

機械学習にも便利なPythonライブラリ「Pandas」の初心者向けチュートリアル

f:id:paiza:20180124123430j:plain
秋山です。

機械学習やディープラーニングが流行っていますが、基本的には何をするにも大量のデータを取り扱いますよね。

データの集計・分析は、機械学習をするのに大前提として必要な作業です。

そんなときに便利なライブラリがPandasです。Pandasは、Pythonを使ったデータ解析に便利な機能を提供しているライブラリです。数値や時系列のデータの操作や、データ構造をいじったりすることができます。

というわけで、今回はそんなPandasを使えるようになりたい初心者の人に向けて、ちょっとしたチュートリアルを書いてみます。

■Pandasって何ぞ

Pandasとは超ざっくり簡単に言うと、Pythonを使って、ExcelやSQL、R言語みたいな感じでデータを取り扱えるようにしてくれる便利なライブラリです。

例えば、データの整列、グループ化、データ同士の結合、スライス、欠損データがあった場合の除外、時系列データの操作…などなどをしてくれます。しかも処理スピードが割と速い。

Pandasを使いこなせるようになれば、超巨大なデータから調査対象となるデータをすぐに絞り込んで整列させる…みたいなことも可能です。

公式ドキュメントはこちら
pandas: powerful Python data analysis toolkit — pandas 0.23.3 documentation

■Pandasを使う前に

環境としては、Python3とJupyterとPandasが既にインストール済みで使える状態になっていることを前提とし進めていきます。

これらを「まだインストールできてない!」という人は、以前書いたこちらの記事を参考にしてください。

【Python3】
paiza.hatenablog.com

【Jupyter】
paiza.hatenablog.com

※Pandasは、Pythonをインストール済の環境であればJupyterと同様に

pip install pandas

でできるはずです。

環境構築が面倒・よくわからないという人は、ブラウザさえあれば使えるクラウド上の開発環境「PaizaCloud」などを使っても実践できます。

PaizaCloudについて詳しくはこちら
https://paiza.cloud

■Pandasを使ってみる

まず、Pandasでよく使うデータオブジェクトは
Series(1次元データ)
DataFrame(2次元データ)
の2つです。特によく見かけるのはDataFrameかなと思います。Pythonで言うとSeriesがリスト、DataFrameが2次元リストといったところです。順番に作ってみましょう。

ちなみにPandasを使うコードでは、 import pandas as pd というように、Pandasをpdの略称で使えるようにすることが多いです。Numpyも import numpy as np とすることが多いですよね。

◆Seriesを作ってみる

まず、1次元配列のSeriesを作ってみます。

import pandas as pd

import numpy as np

python_list = [1,3,5,np.nan,None,-1]

pandas_series  = pd.Series(python_list)

print(python_list)

pandas_series

このコードをPaizaCloudで試すには、まずPaizaCloudに登録・ログインした後、新規サーバ作成で Jupyter Notebook をクリックします。
f:id:paiza:20180123190108p:plain

あとは少し待てば、ブラウザ内にターミナルとブラウザ内ブラウザ(ややこしいですね…)が立ち上がって、これだけでJupyterが使えるようになります。とりあえず、 New からPython3 を選択しましょう。
f:id:paiza:20180123190200p:plain

これで前述のコードを貼りつけて、Jupyter上のRunボタンを押すと…
f:id:paiza:20180123190245p:plain
このような結果が出たと思います。以降、せっかくなのでPaizaCloudを使って動作確認していきます。

こうすると、Numpyのnanや、PythonのNoneなどが、Pandas上では欠損データのNaNとして扱われているのが分かるでしょう。

dtypeという表記が下の方にありますが、これは含まれているデータの型がfloat64(64bit浮動小数)になっていますよという意味です。Noneやnp.nanが含まれるとこうなります。

import pandas as pd
import numpy as np
python_list = [1,3,5,-1]
pandas_series = pd.Series(python_list)
pandas_series

このようにNoneやnp.nanが存在しない場合は、int64として生成されます。

当然ですが、浮動小数を含んでNoneなどを含んでいない場合もfloat64となります。文字列を含んでいたりするとObjectとなり、各要素がそれぞれの型となります。

import pandas as pd
import numpy as np
python_list = [1,3.1,None,'1']
pandas_series = pd.Series(python_list)
pandas_series
print(type(pandas_series[0]))
print(type(pandas_series[1]))
print(type(pandas_series[2]))
print(type(pandas_series[3]))

◆DataFrameを作ってみる

次にDataFrameを作ってみます。

DataFrameは、以下のように二次元配列を与えれば作ることができます。

import pandas as pd
import numpy as np
python_list = [['alice', 100],['bob', 90], ['charlie', 85]]
pandas_dataframe = pd.DataFrame(python_list)
pandas_dataframe

Jupyterだと、表っぽくいい感じに見えるようになっています。


さらに…

import pandas as pd
import numpy as np
python_list = [['alice', 100],['bob', 90], ['charlie', 85]]
pandas_dataframe = pd.DataFrame(python_list, columns=['name', 'score'])
pandas_dataframe

このように、columnsを指定するとさらに見やすくなりますし、以下のように要素を参照できるようになります。
f:id:paiza:20180123190958p:plain
columnsをnameに設定した列に対して、Seriesとして参照することができます。columnsを設定しない場合も、pandas_dataframe[0]などとすることで、一番左の列を参照することが可能です。

◆concat関数を使ってみる

また、SeriesからDataFrameを作ることも可能です。以下のように、concat関数を使えばできます。

import pandas as pd
import numpy as np
names = ['alice', 'bob', 'charlie']
scores = [100, 90, 85]
names_series = pd.Series(names)
scores_series = pd.Series(scores)
pandas_dataframe = pd.concat([names_series, scores_series], axis=1)
pandas_dataframe

concatのaxisは axis=0 がデフォルトで、その場合indexで結合…要するに各Seriesが行として結合されます。axis=1 は列として結合するようになります。

concatに関しては、SeriesだけではなくDataFrameにも使えます。例えば全く同じデータがあったとして、

import pandas as pd
import numpy as np
names = ['alice', 'bob', 'charlie']
scores = [100, 90, 85]
names_series = pd.Series(names)
scores_series = pd.Series(scores)
pandas_dataframe1 = pd.concat([names_series, scores_series], axis=1)

names = ['dave', 'ellen', 'frank']
scores = [20, 80, 95]
names_series = pd.Series(names)
scores_series = pd.Series(scores)
pandas_dataframe2 = pd.concat([names_series, scores_series], axis=1)

pandas_dataframe3 = pd.concat([pandas_dataframe1, pandas_dataframe2])
pandas_dataframe3

とすれば、単純に後ろに繋がる形で連結されます。

concatに関する公式リファレンスはこちらです。

もっと詳しくやりたい人は、ドキュメントの引数などに一通り目を通しておくといいでしょう。

◆mergeを使って結合してみる

次に、DataFrameのmergeを使った結合をいろいろ試してみましょう。

今回は、適当にテスト受験者っぽいサンプルデータを作って使います。各受験者のプロフィール情報がidと紐付いていて、テストの結果はidとともに記録されている…という想定です。

こんな感じで作りました。

import pandas as pd
import numpy as np

names = [{'id':0,'name':'alice','age':21}, {'id':1, 'name':'bob','age':24}, {'id':2, 'name':'charlie','age':22}, {'id':4, 'name':'dave','age':None}]
names_dataframe = pd.DataFrame(names)
names_dataframe

scores = [{'id':0,'score':100, 'retest':True}, {'id':1, 'score':90, 'retest':False}, {'id':2, 'score':85, 'retest':True}, {'id':3, 'score':0, 'retest':False}]
scores_dataframe = pd.DataFrame(scores)
scores_dataframe

names_dataframeはid,name,ageとしてIDと名前と年齢を、scores_dataframeはid,score,retestとしてIDと点数と再テストが必要か否かのデータを持っていると想定します。

上記のようなそれぞれのDataFrameを結合する時は

pd.merge(names_dataframe, scores_dataframe)

とするとだけで、同一columns名のIDで結合して結果を出力できます。ただしscoresの 'id' : 3 は、namesに存在していないために除外されます。


f:id:paiza:20180124115926p:plain
このように

pd.merge(names_dataframe, scores_dataframe, how='right')

とすると…'right'、SQLで言うと'right join'的な形で、 age や name が NaN として結合されました。

テストは受けているけどプロフィールが含まれていない…という人も分析したい場合は、こんな感じになります。逆に、プロフィールはあるけどテストの点数がない…という場合は、 how='left' となります。

howを付けない場合は、どちらかの要素がなくてmergeできないものは全て除外されます。SQLで言うと'inner join'みたいなことですね。

how='outer'を付けると'outer join'となって、両方のデータフレームに存在しないものも含めて、NaNとして結合されます。

…こんな感じで、SQLを使ったことがある人であれば、似たような使い方ができることがわかると思います。

また、今回はIDというcolumns名が共通してあるので明示していませんが、結合するためのキーを指定するには on を使います。例えば

pd.merge(names_dataframe, scores_dataframe, on='id')

もしくはleftとrightを明示して

pd.merge(names_dataframe, scores_dataframe, left_on='id', right='id')

といった感じですね。こうすることで、例えばidとuser_idみたいな感じで、名前は違うけど意味は同じという場合の結合もできます。あんまりないかもしれませんが。

複数キーでマージすることも可能です。以下、scores_dataframeにageカラムを追加してみました。ageはテストを受けた時の年齢として保存されている想定とします。

import pandas as pd
import numpy as np

names = [{'id':0,'name':'alice','age':21}, {'id':1, 'name':'bob','age':24}, {'id':2, 'name':'charlie','age':22}, {'id':4, 'name':'dave','age':None}]
names_dataframe = pd.DataFrame(names)
names_dataframe
scores = [{'id':0,'score':100, 'retest':True, 'age':21}, {'id':1, 'score':90, 'retest':False, 'age':23}, {'id':2, 'score':85, 'retest':True, 'age':22}, {'id':3, 'score':0, 'retest':False, 'age':20}]
scores_dataframe = pd.DataFrame(scores)
scores_dataframe
pd.merge(names_dataframe, scores_dataframe)


こうすると、明示なしでidとageが一致する人とテスト結果のみが出てきます。
f:id:paiza:20180124112855p:plain
前述の通り、 on='id' や on='age' として明示すると、そのカラムのみで結合されます。複数指定の場合、リストでon=['id', 'age']とすることができますので、共通項目は3要素以上あるけど、2要素だけで結合したい場合なども可能となっています。

mergeに関する公式リファレンスはこちら

◆絞り込みをしてみる

次は、pandas上でのデータの絞り込みを試してみましょう。

import pandas as pd
import numpy as np

dataframe = pd.DataFrame(np.random.random_sample(80).reshape((20, 4)), columns=['A', 'B', 'C', 'D'])
dataframe

適当に80個のランダムサンプルデータを作って、4区切りでA,B,C,Dとカラム名を付けます。
f:id:paiza:20180124113204p:plain
こんな感じになりました。DataFrameに対しては、Pythonのリストや辞書のように扱うことが可能です。


まず、A列の10番目から19番目までを絞り込むとこんな感じです。
f:id:paiza:20180124114134p:plain
でも、これぐらいならPythonのリストや辞書で事足りてしまいますよね。

もう少し高度な絞り込みをしてみます…
f:id:paiza:20180124113457p:plain
このように、A列が0.5より大きいものを絞り込んでみました。

さらに高度な絞り込みで、例えば2つの条件で絞り込みたい場合は、各条件を 括弧でくくって、orであれば「|」、andであれば「&」を使います。Pythonの場合、条件文ではandは'and'、orは'or'と書くので少し混乱しますが、pandasでは「|」、「&」と覚えてしまいましょう。言うまでもないですが、 == は一致する値のみを絞り込みます。

orの絞り込み
f:id:paiza:20180124113748p:plain

andの絞り込み
f:id:paiza:20180124113810p:plain


もっと高度な演算子としては、「~」がnot演算子として使えます。こんな感じですね。
f:id:paiza:20180124113907p:plain
ただ、この例であれば (dataframe.B =< 0.5) と同じ意味になりますし、そちらのほうがわかりやすいですね。

他の書き方をするなら、

dataframe.where(dataframe.A > 0.5)

などがありますが、このままでは条件以外のデータをNaNにするということになってしまうので、同じことをするならば

dataframe.where(dataframe.A > 0.5).dropna()

とすると同じ形にデータが加工されます。dropna()は欠損値を除外するものなので覚えておきましょう。

他にも、queryやmaskなどのいろいろな絞り込み方法や演算があるので、興味のある人は自分で試しながら覚えていくといいでしょう。等価な処理になる例も多々あるので、最初は少し混乱するかもしれませんが、自分で手を動かして実践しないとなかなか理解できないですよね。あと、自分でいろいろ試しておいたほうが、後で誰かが書いたコードを見たときに、何を絞り込みたいのかすぐに理解できるようになると思います。

queryやmaskなどに関する公式リファレンスはこちら

■まとめ

というわけでPandasを使っていろいろ遊んでみました。

SQLに触れたことがある人なら、とっつきやすいと思います。今回の記事では、チュートリアル的に駆け足で触ってみた感じなので、もっと詳しく知りたい!という方は、公式リファレンスを参考にしながらいろいろ使ってみると理解が深まると思います。

ほかにもPythonや機械学習関連の記事をいろいろ書いているので、興味のある方は見てみてください。
paiza.hatenablog.com
paiza.hatenablog.com


「Pandasを使うどころかプログラミング自体が初心者なので、まずはPythonを使えるようになりたい!」という方は、プログラミングが動画で学べる「paizaラーニング」の「Python入門編」(今月から全編無料になりました)から始めてみるといいと思います。
paizaラーニング

■動画でプログラミングが学べるpaizaラーニングPython×AI・機械学習入門編が登場!


動画でプログラミングが学べるpaizaラーニングでは、Python、Java、C言語、C#、PHP、Ruby、SQL、JavaScript、HTML/CSSなど、プログラミング初心者でも動画で学べる入門レッスンを公開しています。

そしてこのたび、新たに「Python×AI・機械学習入門編」が追加されました。

人気声優の上坂すみれさんによる進行役のスベトラーナ・小百合・ベレフスカヤと一緒に、実際に画像認識技術を使いながら、初心者でも機械学習を体験・学習できるレッスン内容になっています。

Python×AI・機械学習入門編は全編無料でごらんいただけます。詳しくはこちら



 
PaizaCloud」では、環境構築に悩まされることなく、ブラウザだけで簡単にWebサービスやサーバアプリケーションなどの開発・公開ができます。
https://paiza.cloud

 


 

paizaラーニング」では、未経験者でもブラウザさえあれば、今すぐプログラミングの基礎が動画で学べるレッスンを多数公開しております。

詳しくはこちら

paizaラーニング

そしてpaizaでは、Webサービス開発企業などで求められるコーディング力や、テストケースを想定する力などが問われるプログラミングスキルチェック問題も提供しています。

スキルチェックに挑戦した人は、その結果によってS・A・B・C・D・Eの6段階のランクを取得できます。必要なスキルランクを取得すれば、書類選考なしで企業の求人に応募することも可能です。「自分のプログラミングスキルを客観的に知りたい」「スキルを使って転職したい」という方は、ぜひチャレンジしてみてください。

詳しくはこちら

paizaのスキルチェック