【初心者向け】データ分析で必須のPandasを入門しよう!

Pandasとは

Pandas(パンダス)とは、データ解析を容易にする機能を提供するPythonのデータ解析ライブラリです。
Pandasの特徴には、データフレーム(DataFrame)などの独自のデータ構造が提供されており、様々な処理が可能です。
特に、表形式のデータをSQLまたはRのように操作することが可能で、かつ高速で処理出来ます。
最新情報に関しては 公式ドキュメントを参考してください。

Pandasを使うことで、下記のようなことが出来ます。

CSVやExcel、RDBなどにデータを入出力できる
データ前処理(NaN / Not a Number、欠損値)
データの結合や部分的な取り出しやピボッド(pivot)処理
データの集約及びグループ演算
データに対しての統計処理及び回帰処理

なぜPandasを学ぶのか

なぜPandasを学ぶのかについて説明します。
機械学習においてデータの前処理は多くの時間を割くことになりますが、Pandasを使うことでこのデータの前処理という工程を効率よく行うことが出来ます。
機械学習エンジニアやデータサイエンティストがPythonでデータの前処理をする上で必要なPandasをこの章では説明していきます。

Pandasを使うメリット

Pandasを使うメリットは主に2つあります。
1. 多種の型のデータを一つのデータフレームで扱えること
NumPyの配列(np.array)はすべての要素が同じ型でなければなりません。
よって、csvファイルの読み書きなどでは、NumPyは非常に不便なライブラリです。
その点、Pandasのデータフレームは異なる型のデータを入れることが出来ます。
Pandasのデータフレームに格納することで、データの前処理が容易にできます。
2.データ加工や解析の関数が多いこと
別章で示した欠損値の削除・補完の他にも、これから紹介する様々な便利な関数がPandasには備わっています。
そういった様々な関数の使い方をこの章では学びます。

Pandasのインストール

pipコマンドを用いたPandasのインストールは下記のコマンドでインストール出来ます。
Macの方はターミナル、Windowsの方はコマンドプロンプト上で実行することでインストールが出来ます。

pip install pandas

Jupyter Notebookをお使いの方は、起動したNotebookのセルに、先頭に!マークをつけて実行することでインストールすることが出来ます。

!pip install pandas

Pandasを使う

Pandasを利用するには、Pandasのライブラリを読み込みする必要があります。
以下のコードで、Pandasをpdという名前で扱えるようにしています。

import pandas as pd

データ型(pandasの基本データ型)

PandasはNumPyをベースとして構築されているため、NumPyのndarrayとの相性が良いです。
2つのデータ型でデータを保持します。

1.シリーズ(Series)
2.データフレーム(DataFrame)
1つ1つ見ていきましょう。

シリーズ

Seriesは1列のみのデータ型です。

import pandas as pd
# from pandas import Series

s1 = pd.Series([1,2,3,5])
print(s1)

"""
# 左の列は行ラベル
" 右の列はシリーズのデータ
0    1
1    2
2    3
3    5
dtype: int64 # データの型
"""

シリーズはデータ(values)とそれに対応する行ラベル(index)を持つ1次元データ構造であり、辞書型とは違ってデータには順番があります。

データフレーム

データフレームは2次元のラベル付きのデータ構造で、Pandasでは最も多く使われるデータ型です。
データフレームのイメージとして、スプレッドシートやSQLのテーブルをイメージするとわかりやすいです。
DataFrameは複数の列を持ち、DataFrameから1列を抽出した場合も勝手にSeriesになります。
また、シリーズと同様に様々な型のデータを保持することが出来ます。

import pandas as pd
df = pd.DataFrame({
    '名前' :['田中', '山田', '高橋'],
    '役割' : ['営業部長', '広報部', '技術責任者'],
    '身長' : [178, 173, 169]
    })
print(df)
print(df.dtypes)

print(df.columns) # 列ラベルの確認(辞書型のkeyが列ラベル)

データフレームは、リスト型のデータを持つ辞書型をDataFrame関数の引数に渡すことで、データフレームを生成することが出来ます。
保持されるデータの列の順序ですが、列ラベルによって自動的にソートされます。
ですので、データを与えた時点での順序と異なってしまう可能性があるので注意です。
ですが、columns引数に列の順序を指定することでその通りに作成可能です。

import pandas as pd
data = {
    '名前' :['田中', '山田', '高橋'],
    '役割' : ['営業部長', '広報部', '技術責任者'],
    '身長' : [178, 173, 169]
    }
df = pd.DataFrame(data, columns=["名前", "役割", "身長"]) # データフレーム生成時に対応するデータを持っていない場合、そのデータの列にはNaNが割り当てられます。
# また下記のようにすることで、カラムの名称を変更・置換可能です
df.columns = ["Name", "Position", "height"]
print(df)

head()とtail()

Pandasのデータの中身を見る際に.head()を使うと先頭から5件を表示してくれます。
また引数に数字を渡すことでその件数分先頭から取得可能です。
また、tail()を使うと末尾から5件を取得できます。
head()と同じように、引数に数字を渡すことでその件数分末尾から取得可能です。
またデータの先頭と末尾から同時にデータを確認することも可能です。
その際には、データ.head().append(データ.tail())と記述することで繋げてデータを確認できます。

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(20,2))
df.head() # 先頭から5件
df.tail()   # 末尾から5件

df.head().append(df.tail()) # 先頭から5件と末尾から5件の計10件を取得
df.head(3).append(df.tail(3)) # 先頭から3件と末尾から3件の計6件を取得

locとiloc

Pandasのlocilocは値を抽出するためのメソッドです。
まずはサンプルとなるデータフレームを作成します。

import pandas as pd
df = pd.DataFrame([[10, 20], [25, 50]], index=["1行", "2行"], columns=["1列", "2列"])

まずは、locを使ってみましょう。
locは行名もしくは列名を指定することで特定の値を抽出できます。
1列目と4列目を抽出してみましょう。

pirnt(df.loc["1行", :])

上記を実行すると次のように出力されます。

1列    10
2列    20
Name: 1行, dtype: int64

他にも次のように書くこともできます。

print(df.loc[: , ["1列", "2列"]])

上記を実行すると次のように出力されます。

    1列  2列
1行  10  20
2行  25  50

存在しない列にアクセスするとNaNになります。

print(df.loc[: , ["1列", "5列"]])

上記を実行すると次のように出力されます。

    1列  5列
1行  10 NaN
2行  25 NaN

次にilocを見ていきましょう。
ilocはindexを指定することで特定の値を抽出できます。

# df.iloc[行, 列]
print(df.iloc[1:2])# index指定が可能

上記を実行すると次のように出力されます。

    1列  2列
2行  25  50

また、locilocはスライス表記を用いることが出来るため次のように記述することも可能です。

ilocを使ってスライス表記を書いたプログラムは以下の通りです。

print(df.iloc[:, -1])  # 負のインデックスを使い、末尾の要素から位置指定し2列目の全ての行を取得。
1行    20
2行    50
Name: 2列, dtype: int64

条件による行の抽出(query)

queryを利用することでpandas.DataFrameの列の値に対し、条件に応じて行を抽出することが可能です。
比較演算子を利用した複数の条件指定が出来ます。

import pandas as pd
df = pd.DataFrame([[10, 20,30, 30], [25, 50,65, 80]], index=["1行", "2行"], columns=["A", "B", "C", "D"])
print(df)

上記を実行すると次のように出力されます。

     A   B   C   D
1行  10  20  30  30
2行  25  50  65  80

次に次のコードを書いて実行してみてください。

print(df.query('A >= 5 and C < 50'))

上記を実行すると次のように出力されます。

     A   B   C   D
1行  10  20  30  30

データの入出力

Pnadasには、ファイルを入出力する機能として、大きく4つの機能を提供しています。

1. テキスト形式のデータファイルからデータの読み込み
2. バイナリ形式のデータファイルからデータの読み込み
3. データベースからのデータの読み込み
4. Web上からのデータの読み込み

例えば、Pandasでcsvファイルを読み込む場合は、「read_csv」を使い、データの出力には「to_csv」や「to_excel」などが利用可能です。csv以外にも、「read_json」や「read_excel」、「read_json」「read_sql」もあり、それらの出力メソッドもあります。
TSVファイルの場合は、「read_table」を使うことで区切り文字がタブ\tのファイルを処理することが出来ます。
試しにcsvファイルを読み込んでみましょう。

import pandas as pd
data = pd.read_csv("https://aiacademy.jp/dataset/sample_data.csv",
                   encoding="cp932",
                   skiprows=1, # 1行読み飛ばす
                   )

print(data)
print(type(data)) # <class 'pandas.core.frame.DataFrame'>
print(data.dtypes)

"""
エクセルの場合は下記のように使います。
.read_excel("任意のファイル名.xlsx",encoding='utf8')
"""

Pandas ソート

インデックス (行名・列名)を使う方法と値に基づいてソートする方法があります。
.sort_index()を使うことで、インデックス(カラム名、行名)に基づいてソートを行うことができます。
そのまま使うと、昇順(小さい順)でのソートとなりますが、引数に、ascending=Falseを記述することで降順(大きい順)のソートができます。
.sort_values(by=カラムのリスト)を使うことで、列の値の小さい順にソートすることができます。

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(20,2))
df.sort_index(ascending=False) # 降順

# 昇順でソートするには上記の降順ソートのコードをコメントアウトして下記を実行してください
df.sort_values(by=1) # key(カラム名)が1の昇順(小さい順)でソート
df.sort_values(by=1, ascending=False)  # keyが1の降順(大きい順)でソート

上記を実行すると次のように出力されます。
(random.randn()を用いているため、実行ごとによって出力が変わります。)

           0         1
8  -0.873384  2.444225
12 -1.452744  1.261722
6  -0.024629  1.148419
5  -0.343477  1.130691
18  0.693656  1.098463
13  1.210782  1.064755
14  0.367597  0.777216
0   0.359690  0.699058
1   0.084761  0.479651
4  -0.227558  0.094337
17  0.829182  0.053559
11  0.060647  0.047543
15 -0.247204 -0.413310
16 -0.209684 -0.638343
3  -0.238448 -0.667186
2   1.343385 -0.706601
7  -0.255831 -1.206057
19  0.613618 -1.282351
10 -0.294631 -1.353662
9   0.572267 -1.963924

欠損値の処理

Pandasには欠損値(NaN)の扱うメソッドは「dropna」「fillna」「isnull」「notnull」があります。
1つ1つ解説していきます。
まずdropnaは指定の軸方向にデータ列を見て、欠損値(NaN)の有無に関して指定の条件を満たす場合に、そのデータ列を削除します。
fillnaは欠損値を指定の値もしくは、指定の方法で埋めることができます。
isnullはデータの要素ごとにNaNはTrue、それ以外をFalseとして扱い、元のデータと同じサイズのオブジェクトを返します。
notnullはisnullとは逆の真偽値を返します。

import numpy as np
import pandas as pd
df = pd.DataFrame({"int": [1, np.nan, np.nan, 32],
                   "str": ["python", "ai", np.nan, np.nan],
                   "flt": [5.5, 4.2, -1.2, np.nan]})
print(df)

# df成分に対してNaNの地位をTrueとしたブールの値のデータフレームを返す
print(df.isnull()) # notnull()を使うと、TrueとFalseが逆の処理になる。

# "int"列にNaNがある行の削除
print(df.dropna(subset=["int"]))

# NaNがある行を全て削除する
print(df.dropna())

# NaNを全て0に置換する
print(df.fillna(0)) # 第一引数にmethod="ffill" 第二引数にlimtit=数字 とすることで指定した数字までは前のデータを使ってNaNを埋めることができます

df2 = pd.DataFrame({"int": [1, np.nan, np.nan, 32],
                   "str": ["python", "ai", np.nan, np.nan],
                   "flt": [5.5, 4.2, -1.2, np.nan]})

# int列だけ0で補完
df2.fillna({"int": 0}) # 特定の列に対しては辞書型を用いる


# 列ごとに異なる値を使いたい時は複数のキーを渡す。
df2.fillna({"int": 0, "str": "ai"}) 

# 特定の列(例えばflt)を削除
df2.drop(labels="flt",axis=1)
"""
  int str
0 1.0 python
1 NaN ai
2 NaN NaN
3 32.0  NaN
"""

# 複数の列を削除
df2.drop(labels=["flt", "str"],axis=1)

"""
  int
0 1.0
1 NaN
2 NaN
3 32.0
"""

# indexを指定すると行を消すこともできます
df2.drop(index=1, axis=0)
"""
int str flt
0 1.0 python  5.5
2 NaN NaN -1.2
3 32.0  NaN NaN
"""

# 元のデータに反映して削除するにはinplaceオプションにTrueを渡します
df2.drop(labels="flt", axis=1, inplace=True)
print(df2)

"""
int str
0 1.0 python
1 NaN ai
2 NaN NaN
3 32.0  NaN
"""

ランダムに6行3列のデータを生成するには次のようにします。

import numpy as np
import pandas as pd
df3 = pd.DataFrame(np.random.rand(6,3))
print(df3) # データの確認

まとめ

この章では、Pandasの2つのデータ型(SeriesとDataFrame)やデータの抽出方法や読み込み方法などに関する処理を学んできました。
Pandasにはここでは紹介していないデータ解析を容易にする機能を提供していますので、公式ドキュメントなどを参考にしてさらに使いこなせるようになりましょう。

演習問題

※この章の演習問題では、excelの読み込みを行います。
その際に、ModuleNotFoundError: No module named ‘openpyxl’エラーが出る場合があります。
エラーが出た場合は、pipなどを用いてopenpyxlをインストールしてください。

pip install openpyxl
  1. シリーズのデータ型を自由に作ってください。
  2. データフレームのデータ型を自由に作ってください。
  3. あるSNSサービスのユーザー10人のフォロー数やフォロワー数のcsvファイルがあります。
    このファイルのヘッダーがユーザーID,フォロー,フォロワー,いいねが与えられております。
    これらそれぞれuser_id,follow,follower,likeに変換したoutput.csvファイルを出力してください。
    データは下記URLにありますのでダウンロードしてください。
  4. d1 = {“data1”: [“a”,”b”,”c”,”d”,”c”,”a”], “data2”: range(6)}を使って、d1という名前のDataFrameを作ってください。
  5. 4で作ったデータフレームをcsvファイル(.csv)とエクセルファイル(.xlsx)に書き出してください。
  6. 5で作成されたエクセルファイル(.xlsx)とcsvファイル(.csv)をそれぞれ読み込んでください。
  7. 5で作成したエクセルファイルに新しい列(カラム)を追加してください。
  8. 7に対してappendを使い、行を追加してください。

演習問題回答例
SNSフォローデータ
回答例ソースコード