pandasの基本操作#

はじめに#

本稿ではpandas(Python Data Analysis Library)と呼ばれる、Pythonでのデータ分析を効率的に行うためのライブラリに関して、その基本的な操作方法を紹介します。pandasではデータの読み込み・統計量の算出・整形・可視化・書き出しなど、データ分析で頻出の作業を簡単に行うことができます。また、オープンソース(BSDライセンス)で公開されているため、個人/商用問わず無料で利用できます。

pandasの公式チュートリアルをベースに、基本操作を紹介していきます。 本稿で紹介するpandasの基本操作は以下の通りです。

  • オブジェクトの作成

  • データの確認

  • データの取得

  • 欠損データの処理

  • データの操作

  • データの結合

  • グルーピング

  • 時系列データの処理

  • データの可視化

  • データの書き出し・読み込み

オブジェクトの作成#

本章では、データを格納するオブジェクトの作成方法を紹介します。データをpandasのオブジェクトに格納することで、pandasが提供する、分析を効率化するためのさまざまな機能を利用できるようになります。

データを格納するオブジェクトには、主にSeriesとDataFrameの2種類存在します。簡単に言えば、Seriesは一次元配列、DataFrameは二次元配列です。ただし、連番以外の「インデックス」を持つことができるなど、同様のデータオブジェクト(組み込み型のlistやNumPyの二次元配列)よりも高い機能を有しています。

それでは、早速オブジェクトを作成してみましょう。

  • Seriesオブジェクトの作成

  • DataFrameオブジェクトの作成

import numpy as np
import pandas as pd  # 慣例としてpdという略称で定義する

Seriesオブジェクトの作成#

pandasの Series() 関数によって、Seriesオブジェクトを作成できます。さまざまな引数がありますが、ここでは主要なもののみを紹介します。(詳細は公式ページ)

pandas.Series(data=None, index=None, name=None)

  • data : Seriesオブジェクトに渡すデータを指定( list やNumPyの一次元配列など)

  • index : Seriesオブジェクトに渡すインデックスを指定( list やNumPyの一次元配列など)

  • name : Seriesオブジェクトの名前を指定( str

# Seriesオブジェクトの作成
s = pd.Series([1, 3, 5, np.nan, 6, 8])
display(s)
0    1.0
1    3.0
2    5.0
3    NaN
4    6.0
5    8.0
dtype: float64

DataFrameオブジェクトの作成#

pandasの DataFrame() 関数によって、DataFrameオブジェクトを作成できます。さまざまな引数がありますが、ここでは主要なもののみを紹介します。(詳細は公式ページ)

pandas.DataFrame(data=None, index=None, columns=None)

  • data : DataFrameオブジェクトに渡すデータを指定(NumPyの二次元配列など)

  • index : DataFrameオブジェクトに渡すインデックスを指定( list やNumPyの一次元配列など)

  • columns : DataFrameオブジェクトに渡すカラム名を指定( list やNumPyの一次元配列など)

# DataFrameのインデックスをDatetime型で作成
dates = pd.date_range("20130101", periods=6)
display(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')
# DataFrameオブジェクトの作成
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list("ABCD"))
display(df)
A B C D
2013-01-01 0.166328 -2.136717 -1.079066 0.412360
2013-01-02 -0.346681 -0.426526 0.518986 -0.608594
2013-01-03 0.305456 -0.382561 0.723871 -0.209471
2013-01-04 -0.788086 0.588946 1.426202 0.289746
2013-01-05 -0.503083 0.567122 1.287743 -0.014255
2013-01-06 0.299511 -1.941320 1.391943 1.173333
# DataFrameオブジェクトはdict型データからも作成可能
# また、カラムごとに異なるデータ型を持たせることも可能
df2 = pd.DataFrame(
    {
        "A": 1.0,
        "B": pd.Timestamp("20130102"),
        "C": pd.Series(1, index=list(range(4)), dtype="float32"),
        "D": np.array([3] * 4, dtype="int32"),
        "E": pd.Categorical(["test", "train", "test", "train"]),
        "F": "foo",
    }
)

display(df2)
display(df2.dtypes)
A B C D E F
0 1.0 2013-01-02 1.0 3 test foo
1 1.0 2013-01-02 1.0 3 train foo
2 1.0 2013-01-02 1.0 3 test foo
3 1.0 2013-01-02 1.0 3 train foo
A           float64
B    datetime64[ns]
C           float32
D             int32
E          category
F            object
dtype: object

データ確認#

本章では、オブジェクトに格納したデータを確認するさまざまな方法を紹介します。紹介する内容は以下の通りです。

  • 先頭数行・終端数行の確認

  • インデックス・カラムの確認

  • NumPyの二次元配列形式に変換して確認

  • データの統計量の確認

  • データを転置して確認

  • 特定の軸・要素に対して降順・昇順に並べ替えて確認

先頭数行・終端数行の確認#

Series、DataFrameの head() メソッドによって先頭\(n\)行を、 tail() メソッドによって終端\(n\)行を確認できます。

DataFrame.head(n=5) (詳細は公式ページ

  • n : 先頭から取り出す行数を指定(デフォルトは5)

DataFrame.tail(n=5) (詳細は公式ページ

  • n : 終端から取り出す行数を指定(デフォルトは5)

# 先頭数行の確認
display(df.head())  # デフォルトは先頭5行分
A B C D
2013-01-01 0.166328 -2.136717 -1.079066 0.412360
2013-01-02 -0.346681 -0.426526 0.518986 -0.608594
2013-01-03 0.305456 -0.382561 0.723871 -0.209471
2013-01-04 -0.788086 0.588946 1.426202 0.289746
2013-01-05 -0.503083 0.567122 1.287743 -0.014255
# 終端数行の確認
display(df.tail(3))  # 引数に整数を指定すると、その分の行を確認できる
A B C D
2013-01-04 -0.788086 0.588946 1.426202 0.289746
2013-01-05 -0.503083 0.567122 1.287743 -0.014255
2013-01-06 0.299511 -1.941320 1.391943 1.173333

インデックス・カラムの確認#

Series、DataFrameの index プロパティによってインデックスを、DataFrameの columns プロパティによってカラムを確認できます。

DataFrame.index (詳細は公式ページ

DataFrame.columns (詳細は公式ページ

# インデックスの確認
display(df.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')
# カラムの確認
display(df.columns)
Index(['A', 'B', 'C', 'D'], dtype='object')

NumPyの二次元配列形式に変換して確認#

DataFrameの to_numpy() メソッドによってNumPyの二次元配列形式に変換して確認できます。なお、変換された二次元配列にはインデックスとカラムは含まれません。

DataFrame.to_numpy() (詳細は公式ページ

# NumPyの二次元配列に変換して確認
# なお、変換された二次元配列にはインデックスとカラムは含まれない
display(df.to_numpy())
display(df2.to_numpy())
array([[ 0.16632788, -2.13671679, -1.07906646,  0.41235954],
       [-0.34668051, -0.42652624,  0.51898578, -0.6085936 ],
       [ 0.30545645, -0.38256099,  0.72387141, -0.20947113],
       [-0.78808582,  0.58894566,  1.42620156,  0.28974615],
       [-0.50308337,  0.56712154,  1.28774348, -0.01425486],
       [ 0.29951098, -1.94132013,  1.3919435 ,  1.17333286]])
array([[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'test', 'foo'],
       [1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'train', 'foo'],
       [1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'test', 'foo'],
       [1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'train', 'foo']],
      dtype=object)

データの統計量の確認#

DataFrameの describe() メソッドによってデータの統計量を確認できます。具体的には、数値データカラムに対して、個数・平均標準偏差・各種パーセンタイル値を確認できます。

DataFrame.describe() (詳細は公式ページ

# データの統計量の確認
# 数値データカラムに対して、個数・平均・標準偏差・各種パーセンタイル値を確認できる
display(df.describe())
A B C D
count 6.000000 6.000000 6.000000 6.000000
mean -0.144426 -0.621843 0.711613 0.173853
std 0.464733 1.184138 0.953855 0.610544
min -0.788086 -2.136717 -1.079066 -0.608594
25% -0.463983 -1.562622 0.570207 -0.160667
50% -0.090176 -0.404544 1.005807 0.137746
75% 0.266215 0.329701 1.365893 0.381706
max 0.305456 0.588946 1.426202 1.173333

データを転置して確認#

DataFrameの T プロパティによってデータを転置して確認できます。

DataFrame.T (詳細は公式ページ

# データを転置して確認
display(df.T)
2013-01-01 2013-01-02 2013-01-03 2013-01-04 2013-01-05 2013-01-06
A 0.166328 -0.346681 0.305456 -0.788086 -0.503083 0.299511
B -2.136717 -0.426526 -0.382561 0.588946 0.567122 -1.941320
C -1.079066 0.518986 0.723871 1.426202 1.287743 1.391943
D 0.412360 -0.608594 -0.209471 0.289746 -0.014255 1.173333

特定の軸・要素に対して降順・昇順に並べ替えて確認#

Series、DataFrameの sort_index() メソッドによって特定の軸に沿って並べ替えて、 sort_values() メソッドによって要素の値に応じて並べ替えて確認することができます。それぞれさまざまな引数がありますが、ここでは主要なもののみを紹介します。

DataFrame.sort_index(axis=0, ascending=True) (詳細は公式ページ

  • axis : 要素を並べ替える軸を選択(デフォルトはインデックス方向)

  • ascending: 昇順・降順を選択(デフォルトは昇順、 True or False

DataFrame.sort_values(by, axis=0, ascending=True) (詳細は公式ページ

  • by : 要素を並べ替える基準カラムを選択( strlist など)

  • axis : 要素を並べ替える軸を選択(デフォルトはインデックス方向)

  • ascending: 昇順・降順を選択(デフォルトは昇順、 True or False

# 特定の軸に対して降順に並べ替えて確認
# デフォルトはインデックス方向・昇順だが、ここではカラム方向・降順で並べ替える
display(df.sort_index(axis=1, ascending=False))
D C B A
2013-01-01 0.412360 -1.079066 -2.136717 0.166328
2013-01-02 -0.608594 0.518986 -0.426526 -0.346681
2013-01-03 -0.209471 0.723871 -0.382561 0.305456
2013-01-04 0.289746 1.426202 0.588946 -0.788086
2013-01-05 -0.014255 1.287743 0.567122 -0.503083
2013-01-06 1.173333 1.391943 -1.941320 0.299511
# 特定の要素に対して昇順に並べ替えて確認
display(df.sort_values(by="B"))
A B C D
2013-01-01 0.166328 -2.136717 -1.079066 0.412360
2013-01-06 0.299511 -1.941320 1.391943 1.173333
2013-01-02 -0.346681 -0.426526 0.518986 -0.608594
2013-01-03 0.305456 -0.382561 0.723871 -0.209471
2013-01-05 -0.503083 0.567122 1.287743 -0.014255
2013-01-04 -0.788086 0.588946 1.426202 0.289746

データの取得#

本章では、オブジェクトに格納したデータを取得する方法を紹介します。紹介する内容は以下の通りです。なお、要素の追加・置換に関しても紹介します。

  • カラム選択やスライスによるデータ取得

  • ラベル指定で取得

  • 位置指定で取得

  • Booleanで取得

  • 要素の追加・置換

カラム選択やスライスによる取得#

# カラム選択によるデータ取得
display(df["A"])  # df.Aでも可能
2013-01-01    0.166328
2013-01-02   -0.346681
2013-01-03    0.305456
2013-01-04   -0.788086
2013-01-05   -0.503083
2013-01-06    0.299511
Freq: D, Name: A, dtype: float64
# インデックス方向に対してスライスで取得
# インデックスの位置やラベルでの指定が可能
display(df[0:3])
display(df["20130102":"20130104"])
A B C D
2013-01-01 0.166328 -2.136717 -1.079066 0.412360
2013-01-02 -0.346681 -0.426526 0.518986 -0.608594
2013-01-03 0.305456 -0.382561 0.723871 -0.209471
A B C D
2013-01-02 -0.346681 -0.426526 0.518986 -0.608594
2013-01-03 0.305456 -0.382561 0.723871 -0.209471
2013-01-04 -0.788086 0.588946 1.426202 0.289746

ラベル指定で取得#

DataFrameの loc プロパティ、at プロパティによって、ラベル指定によるデータ取得ができます。

DataFrame.loc (詳細は公式ページ

DataFrame.at (詳細は公式ページ

# 特定インデックスの取得
display(df.loc[dates[0]])  # dates[0] = '20130101'
A    0.166328
B   -2.136717
C   -1.079066
D    0.412360
Name: 2013-01-01 00:00:00, dtype: float64
# 特定インデックス・カラムの取得
display(df.loc[:, ["A", "B"]])
display(df.loc["20130102":"20130104", ["A", "B"]])
display(df.loc["20130102", ["A", "B"]])
display(df.loc[dates[0], "A"])
A B
2013-01-01 0.166328 -2.136717
2013-01-02 -0.346681 -0.426526
2013-01-03 0.305456 -0.382561
2013-01-04 -0.788086 0.588946
2013-01-05 -0.503083 0.567122
2013-01-06 0.299511 -1.941320
A B
2013-01-02 -0.346681 -0.426526
2013-01-03 0.305456 -0.382561
2013-01-04 -0.788086 0.588946
A   -0.346681
B   -0.426526
Name: 2013-01-02 00:00:00, dtype: float64
0.16632787659365253
# 特定の1要素をラベル指定で取得する場合は、atの方が高速
display(df.at[dates[0], "A"])
0.16632787659365253

位置指定で取得#

DataFrameの iloc プロパティ、iat プロパティによって、位置指定によるデータ取得ができます。

DataFrame.iloc (詳細は公式ページ

DataFrame.iat (詳細は公式ページ

# 特定行の取得
display(df.iloc[3])
A   -0.788086
B    0.588946
C    1.426202
D    0.289746
Name: 2013-01-04 00:00:00, dtype: float64
# 特定行・列の取得
display(df.iloc[3:5, 0:2])
display(df.iloc[[1, 2, 4], [0, 2]])
display(df.iloc[1:3, :])
display(df.iloc[:, 1:3])
display(df.iloc[1, 1])
A B
2013-01-04 -0.788086 0.588946
2013-01-05 -0.503083 0.567122
A C
2013-01-02 -0.346681 0.518986
2013-01-03 0.305456 0.723871
2013-01-05 -0.503083 1.287743
A B C D
2013-01-02 -0.346681 -0.426526 0.518986 -0.608594
2013-01-03 0.305456 -0.382561 0.723871 -0.209471
B C
2013-01-01 -2.136717 -1.079066
2013-01-02 -0.426526 0.518986
2013-01-03 -0.382561 0.723871
2013-01-04 0.588946 1.426202
2013-01-05 0.567122 1.287743
2013-01-06 -1.941320 1.391943
-0.4265262397519023
# 特定の1要素を位置指定で取得する場合は、iatの方が高速
display(df.iat[1, 1])
-0.4265262397519023

Booleanで取得#

# あるカラムに対するBooleanで取得
# ここでは、dfのAカラムの値が0より大きいインデックスのみを抽出
display(df["A"] > 0)
display(df[df["A"] > 0])
2013-01-01     True
2013-01-02    False
2013-01-03     True
2013-01-04    False
2013-01-05    False
2013-01-06     True
Freq: D, Name: A, dtype: bool
A B C D
2013-01-01 0.166328 -2.136717 -1.079066 0.412360
2013-01-03 0.305456 -0.382561 0.723871 -0.209471
2013-01-06 0.299511 -1.941320 1.391943 1.173333
# DataFrame全体に対するBooleanで取得
# ここでは、dfの0より大きい要素のみ値を抽出
display(df > 0)
display(df[df > 0])
A B C D
2013-01-01 True False False True
2013-01-02 False False True False
2013-01-03 True False True False
2013-01-04 False True True True
2013-01-05 False True True False
2013-01-06 True False True True
A B C D
2013-01-01 0.166328 NaN NaN 0.412360
2013-01-02 NaN NaN 0.518986 NaN
2013-01-03 0.305456 NaN 0.723871 NaN
2013-01-04 NaN 0.588946 1.426202 0.289746
2013-01-05 NaN 0.567122 1.287743 NaN
2013-01-06 0.299511 NaN 1.391943 1.173333

要素の追加・置換#

# Seriesを作成
s1 = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range("20130102", periods=6))
display(s1)

# 作成したSeriesを新たにdfのFカラムとして追加(インデックスが合致する部分のみ)
df["F"] = s1

# dfの0行1列目の要素を0に置換
df.iat[0, 1] = 0

# dfのDカラムの要素をすべて5で置換
df.loc[:, "D"] = np.array([5] * len(df))

display(df)
2013-01-02    1
2013-01-03    2
2013-01-04    3
2013-01-05    4
2013-01-06    5
2013-01-07    6
Freq: D, dtype: int64
A B C D F
2013-01-01 0.166328 0.000000 -1.079066 5 NaN
2013-01-02 -0.346681 -0.426526 0.518986 5 1.0
2013-01-03 0.305456 -0.382561 0.723871 5 2.0
2013-01-04 -0.788086 0.588946 1.426202 5 3.0
2013-01-05 -0.503083 0.567122 1.287743 5 4.0
2013-01-06 0.299511 -1.941320 1.391943 5 5.0

欠損データの処理#

本章では、欠損データの処理方法を紹介します。紹介する内容は以下の通りです。

  • 欠損データの削除

  • 欠損データの置換

  • 欠損データ位置の検索

欠損データの削除#

Series、DataFrameの dropna() メソッドによって欠損データを削除することができます。さまざまな引数がありますが、ここでは主要なもののみを紹介します。

DataFrame.dropna(axis=0, how='any') (詳細は公式ページ

  • axis : 要素を削除する軸を選択(デフォルトはインデックス方向)

  • how : 削除方法を anyall から選択(デフォルトは any

    • any : 一つでも欠損データがあれば対象インデックス/カラムを削除

    • all : すべてが欠損データであれば対象インデックス/カラムを削除

# 欠損を含むデータの作成
df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ["E"])
df1.loc[dates[0] : dates[1], "E"] = 1
display(df1)
A B C D F E
2013-01-01 0.166328 0.000000 -1.079066 5 NaN 1.0
2013-01-02 -0.346681 -0.426526 0.518986 5 1.0 1.0
2013-01-03 0.305456 -0.382561 0.723871 5 2.0 NaN
2013-01-04 -0.788086 0.588946 1.426202 5 3.0 NaN
# 欠損データの削除
# 欠損が含まれるインデックスを削除
display(df1.dropna(how="any"))
A B C D F E
2013-01-02 -0.346681 -0.426526 0.518986 5 1.0 1.0

欠損データの置換#

Series、DataFrameの fillna() メソッドによって欠損データを任意の値で置換することができます。さまざまな引数がありますが、ここでは主要なもののみを紹介します。

DataFrame.fillna(value=None, method=None) (詳細は公式ページ

  • value : 置換する値を設定

  • method : 置換方法を bfillffill などから選択

    • bfill : 前の要素と同じ値で置換

    • ffill : 後の要素と同じ値で置換

# 欠損データを任意の値で置換
display(df1.fillna(value=5))
A B C D F E
2013-01-01 0.166328 0.000000 -1.079066 5 5.0 1.0
2013-01-02 -0.346681 -0.426526 0.518986 5 1.0 1.0
2013-01-03 0.305456 -0.382561 0.723871 5 2.0 5.0
2013-01-04 -0.788086 0.588946 1.426202 5 3.0 5.0

欠損データ位置の検索#

pandasの isna() 関数によって欠損データ位置を True 、その他を False とするDataFrameを取得することができます。

pandas.isna() (詳細は公式ページ

# 欠損データ位置の検索
display(pd.isna(df1))
A B C D F E
2013-01-01 False False False False True False
2013-01-02 False False False False False False
2013-01-03 False False False False False True
2013-01-04 False False False False False True

データの操作#

本章では、データの操作方法を紹介します。紹介する内容は以下の通りです。

  • 統計量の算出

  • データ変換

  • 度数算出

統計量の算出#

Series、DataFrameには要素の統計量を算出するさまざまなメソッドが存在します。

  • DataFrame.mean(axis=0) : 平均値を算出

  • DataFrame.std(axis=0) : 標準偏差を算出

  • DataFrame.var(axis=0) : 分散を算出

  • DataFrame.sum(axis=0) : 合計値を算出

  • DataFrame.min(axis=0) : 最小値を抽出

  • DataFrame.max(axis=0) : 最大値を抽出

  • DataFrame.median(axis=0) : 中央値を抽出

  • DataFrame.mode(axis=0) : 最頻値を抽出

なお、デフォルトはカラム方向に統計量を算出しますが、 axis=1 とすると、インデックス方向に統計量を算出します。

# 平均値の算出
display(df.mean())  # デフォルトはカラムに対する平均値となる
A   -0.144426
B   -0.265723
C    0.711613
D    5.000000
F    3.000000
dtype: float64
display(df.mean(axis=1))  # axis=1とするとインデックスに対する平均値となる
2013-01-01    1.021815
2013-01-02    1.149156
2013-01-03    1.529353
2013-01-04    1.845412
2013-01-05    2.070356
2013-01-06    1.950027
Freq: D, dtype: float64

データ変換#

Series、DataFrameの apply() メソッドによって任意の関数でデータを変換することができます。さまざまな引数がありますが、ここでは主要なもののみを紹介します。

DataFrame.apply(func, axis=0) (詳細は公式ページ

  • func : 変換関数を指定

  • axis : 関数を適用する軸を選択(デフォルトはインデックス方向)

# NumPyの関数をデータし変換
display(df.apply(np.cumsum))  # NumPyのcumsum関数(累積和算出)を適用
A B C D F
2013-01-01 0.166328 0.000000 -1.079066 5 NaN
2013-01-02 -0.180353 -0.426526 -0.560081 10 1.0
2013-01-03 0.125104 -0.809087 0.163791 15 3.0
2013-01-04 -0.662982 -0.220142 1.589992 20 6.0
2013-01-05 -1.166065 0.346980 2.877736 25 10.0
2013-01-06 -0.866554 -1.594340 4.269679 30 15.0
# ユーザーが定義した関数も適用可能
display(df.apply(lambda x: x.max() - x.min()))  # カラムごとに最大値と最小値の差を算出
A    1.093542
B    2.530266
C    2.505268
D    0.000000
F    4.000000
dtype: float64

度数算出#

Seriesの value_counts() メソッドによって含まれる各要素の度数を算出できます。

Series.value_counts() (詳細は公式ページ

# カラムごとにユニークな要素の度数を算出する
s = pd.Series(np.random.randint(0, 7, size=10))
display(s)
display(s.value_counts())
0    3
1    6
2    4
3    2
4    3
5    5
6    1
7    4
8    6
9    3
dtype: int64
3    3
6    2
4    2
5    1
2    1
1    1
dtype: int64

データの結合#

本章では、データの結合方法を紹介します。紹介する内容は以下の通りです。

  • Concat

  • Join

Concat#

pandasの concat() 関数によって、複数のpandasオブジェクト(Series、DataFrame)を連結できます。さまざまな引数がありますが、ここでは主要なもののみを紹介します。

pandas.concat(objs, axis=0, ignore_index=True) (詳細は公式ページ

  • objs : 連結するpandasオブジェクトをまとめたもの

  • axis : pandasオブジェクトを連結する方向(デフォルトはインデックス方向)

  • ignore_index : 連結前のインデックスを保持するかを設定(デフォルトは保持する、 True or False

    • True : インデックスを新たに振り直す(先頭から0、1、2、、、)

    • False : 連結前のインデックスを保持する

# 複数のpandasオブジェクト(Series、DataFrame)を連結
# まず、適当なDataFrameを作成
df = pd.DataFrame(np.random.randn(10, 4))
display(df)
0 1 2 3
0 0.806613 -1.919551 0.010989 -1.386274
1 -0.485257 -0.867472 -0.452377 -0.100792
2 -0.555209 -1.594025 0.094861 -0.921013
3 1.815996 0.445259 0.002511 0.950379
4 -1.045618 -0.510390 0.739795 0.220217
5 1.089392 0.054136 0.793023 -0.614540
6 -0.448433 0.869446 -1.101350 0.500749
7 -0.258171 0.971561 0.417669 0.253375
8 -0.099999 0.200793 -0.153091 -0.254538
9 0.080026 0.231965 1.085134 -0.841865
# 作成したDataFrameを適当に分割し、listに格納
pieces = [df[:3], df[3:7], df[7:]]
display(pieces)
[          0         1         2         3
 0  0.806613 -1.919551  0.010989 -1.386274
 1 -0.485257 -0.867472 -0.452377 -0.100792
 2 -0.555209 -1.594025  0.094861 -0.921013,
           0         1         2         3
 3  1.815996  0.445259  0.002511  0.950379
 4 -1.045618 -0.510390  0.739795  0.220217
 5  1.089392  0.054136  0.793023 -0.614540
 6 -0.448433  0.869446 -1.101350  0.500749,
           0         1         2         3
 7 -0.258171  0.971561  0.417669  0.253375
 8 -0.099999  0.200793 -0.153091 -0.254538
 9  0.080026  0.231965  1.085134 -0.841865]
# listに格納されたDataFrameを、インデックス方向に連結
display(pd.concat(pieces))
0 1 2 3
0 0.806613 -1.919551 0.010989 -1.386274
1 -0.485257 -0.867472 -0.452377 -0.100792
2 -0.555209 -1.594025 0.094861 -0.921013
3 1.815996 0.445259 0.002511 0.950379
4 -1.045618 -0.510390 0.739795 0.220217
5 1.089392 0.054136 0.793023 -0.614540
6 -0.448433 0.869446 -1.101350 0.500749
7 -0.258171 0.971561 0.417669 0.253375
8 -0.099999 0.200793 -0.153091 -0.254538
9 0.080026 0.231965 1.085134 -0.841865

Join#

DataFrameの join() メソッドによって、あるDataFrameと別のpandasオブジェクトをSQL-likeに連結できます。さまざまな引数がありますが、ここでは主要なもののみを紹介します。

DataFrame.concat(other, on=None, how='left') (詳細は公式ページ

  • other : 連結対象のpandasオブジェクト(Series、DataFrame)

  • on : キーとするカラム名を設定

  • how : データの連結方法の選択(デフォルトは leftleft or right or outer or inner

# SQL-likeにデータを結合することも可能
left = pd.DataFrame({"key": ["foo", "foo"], "lval": [1, 2]})
right = pd.DataFrame({"key": ["foo", "foo"], "rval": [4, 5]})
display(left)
display(right)

display(pd.merge(left, right, on="key"))
key lval
0 foo 1
1 foo 2
key rval
0 foo 4
1 foo 5
key lval rval
0 foo 1 4
1 foo 1 5
2 foo 2 4
3 foo 2 5
# もう一例紹介
left = pd.DataFrame({"key": ["foo", "bar"], "lval": [1, 2]})
right = pd.DataFrame({"key": ["foo", "bar"], "rval": [4, 5]})
display(left)
display(right)

display(pd.merge(left, right, on="key"))
key lval
0 foo 1
1 bar 2
key rval
0 foo 4
1 bar 5
key lval rval
0 foo 1 4
1 bar 2 5

グルーピング#

本章では、データのグルーピング方法を紹介します。データをグルーピングし、各グループの特徴(例えば統計量など)を簡単に算出することができます。

具体的には、DataFrameの groupby() メソッド(詳細は公式ページ)によってグルーピングを簡単に行うことができます。グルーピング処理は以下の手順で行われます。

  • データを任意の基準に従って分割

  • 分割したデータグループそれぞれに対し、任意の関数を適用

  • 関数を適用した結果を結合

# まず、適当なDataFrameを作成
df = pd.DataFrame(
    {
        "A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo", "bar"],
        "B": ["one", "one", "two", "three", "two", "two", "one", "three"],
        "C": np.random.randn(8),
        "D": np.random.randn(8),
    }
)
display(df)
A B C D
0 foo one 0.687179 -0.717884
1 bar one 3.079297 0.699311
2 foo two -1.566509 -0.491073
3 bar three 1.063598 0.943438
4 foo two -1.060167 0.795170
5 bar two 0.750331 1.370753
6 foo one 0.271376 -0.181413
7 bar three -0.942895 -0.207787
# データをカラムAの要素に従ってグルーピングし、それぞれの合計値を算出
display(df.groupby("A").sum())
C D
A
bar 3.950331 2.805715
foo -1.668122 -0.595200
# 複数カラムを指定することも可能
display(df.groupby(["A", "B"]).sum())
C D
A B
bar one 3.079297 0.699311
three 0.120703 0.735651
two 0.750331 1.370753
foo one 0.958555 -0.899297
two -2.626676 0.304097

時系列データの処理#

本章では、時系列データの処理方法を紹介します。なお、時系列データの定義は DatetimeIndex を持つpandasオブジェクト(Series、DataFrame)とします。DatetimeIndex を持つことで、データのリサンプリングなどを簡単に実施することができます。

# まず、適当な時系列データを作成
rng = pd.date_range("1/1/2012", periods=100, freq="S")
ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
display(ts)
2012-01-01 00:00:00    185
2012-01-01 00:00:01    292
2012-01-01 00:00:02    261
2012-01-01 00:00:03    493
2012-01-01 00:00:04    180
                      ... 
2012-01-01 00:01:35    153
2012-01-01 00:01:36    300
2012-01-01 00:01:37     84
2012-01-01 00:01:38     41
2012-01-01 00:01:39     73
Freq: S, Length: 100, dtype: int64
# 時系列データを任意の時間間隔とする
# ここでは、5分間隔で再集計し、その合計値を要素として扱う
display(ts.resample("5Min").sum())
2012-01-01    23810
Freq: 5T, dtype: int64
# タイムゾーンの設定・変更も可能
rng = pd.date_range("3/6/2012 00:00", periods=5, freq="D")
ts = pd.Series(np.random.randn(len(rng)), rng)
display(ts)
2012-03-06   -0.301987
2012-03-07    0.390751
2012-03-08    0.900278
2012-03-09   -1.092933
2012-03-10   -1.899672
Freq: D, dtype: float64
# UTC(協定世界時)に設定
ts_utc = ts.tz_localize("UTC")
display(ts_utc)
2012-03-06 00:00:00+00:00   -0.301987
2012-03-07 00:00:00+00:00    0.390751
2012-03-08 00:00:00+00:00    0.900278
2012-03-09 00:00:00+00:00   -1.092933
2012-03-10 00:00:00+00:00   -1.899672
Freq: D, dtype: float64
# US/Eastern(アメリカ東部標準時)に変換(UTC - 5時間)
display(ts_utc.tz_convert("US/Eastern"))
2012-03-05 19:00:00-05:00   -0.301987
2012-03-06 19:00:00-05:00    0.390751
2012-03-07 19:00:00-05:00    0.900278
2012-03-08 19:00:00-05:00   -1.092933
2012-03-09 19:00:00-05:00   -1.899672
Freq: D, dtype: float64
# さまざまな時間表現が可能
# yyyy-mm-dd
rng = pd.date_range("1/1/2012", periods=5, freq="M")
ts = pd.Series(np.random.randn(len(rng)), index=rng)
display(ts)
2012-01-31    0.959458
2012-02-29    0.295099
2012-03-31    0.665237
2012-04-30    0.115700
2012-05-31    1.622997
Freq: M, dtype: float64
# yyyy-mm
ps = ts.to_period()
display(ps)
2012-01    0.959458
2012-02    0.295099
2012-03    0.665237
2012-04    0.115700
2012-05    1.622997
Freq: M, dtype: float64
# yyyy-mm-01
display(ps.to_timestamp())
2012-01-01    0.959458
2012-02-01    0.295099
2012-03-01    0.665237
2012-04-01    0.115700
2012-05-01    1.622997
Freq: MS, dtype: float64
# 四半期単位での時間表現も可能
prng = pd.period_range("1990Q1", "2000Q4", freq="Q-NOV")
ts = pd.Series(np.random.randn(len(prng)), prng)
ts.index = (prng.asfreq("M", "e") + 1).asfreq("H", "s") + 9
display(ts.head())
1990-03-01 09:00    1.182331
1990-06-01 09:00   -0.538331
1990-09-01 09:00   -0.279225
1990-12-01 09:00   -0.286005
1991-03-01 09:00    0.897384
Freq: H, dtype: float64

データの可視化#

本章では、データの可視化方法を紹介します。pandasの可視化メソッドはMatplotlibのラッパーであり、Matplotlibよりも簡易に可視化を行うことができます。

基本的に、Series、DataFrameの plot() メソッドを使うことで可視化を行うことができます。 折れ線グラフによる可視化を紹介しますが、ほかにも散布図や箱ひげ図など、さまざまな可視化を行うことができます。(詳細はこちらのサイト

# pandasの可視化メソッドを使うために、matplotlibをインポート
import matplotlib.pyplot as plt

%matplotlib inline
# ランダムウォークする時系列データを作成
ts = pd.Series(np.random.randn(1000), index=pd.date_range("1/1/2000", periods=1000))
ts = ts.cumsum()
ts.plot()  # Series.plot()により、インデックスをx軸、要素をy軸とした折れ線グラフを作成できる
<matplotlib.axes._subplots.AxesSubplot at 0x11a7f9790>
../_images/6cf9adf72bd03c7727e18d71a808690e34da3f20e833c3b1c4d3d01cca1a00c4.png
# 4つのランダムウォークする時系列データを作成
df = pd.DataFrame(
    np.random.randn(1000, 4), index=ts.index, columns=["A", "B", "C", "D"]
)
df = df.cumsum()

plt.figure()
df.plot()  # DataFrame.plot()によりインデックスをx軸、各カラム要素をy軸とした折れ線グラフを作成できる
plt.legend(loc="best")
<matplotlib.legend.Legend at 0x11a600c90>
<Figure size 432x288 with 0 Axes>
../_images/778348346f90cac3ff9451c80a5fb316b4e94564b7bcc7c47f93e1dbaf956dae.png

データの書き出し・読み込み#

本章では、データの書き出し・読み込み方法を紹介します。紹介する内容は以下の通りです

  • CSV

  • Excel

CSV形式#

Series、DataFrameの to_csv() メソッドによってCSV形式での書き込みが、pandasの read_csv() 関数によってCSV形式データの読み込みができます。それぞれさまざまな引数が存在しますが、ここでは主要なもののみを紹介します。

DataFrame.to_csv(path=None, columns=None, index=True) (詳細は公式ページ

  • path : 書き出し先のファイルパス( str など)

  • columns : 書き出し対象のカラムを設定( strint など、 list での設定が可能)

  • index : 行番号を書き出すかを選択(デフォルトは書き出す、 True or False

pandas.read_csv(filepath, index_col=None, usecols, parse_dates=False) (詳細は公式ページ

  • filepath : 読み込み対象のCSVファイルパス( str など)

  • index_col : インデックスとしたカラムを設定( strint など、 list での設定が可能)

  • usecols : 読み込みたいカラムを設定( strint など、 list での設定が可能)

  • parse_dates : Datetime としたいカラムを設定( strint など、 list での設定が可能)

# csv形式でのデータ書き込み
df.to_csv("foo.csv")

# csv形式データの読み込み
display(pd.read_csv("foo.csv"))
Unnamed: 0 A B C D
0 2000-01-01 1.943932 -0.208172 0.173399 -0.877959
1 2000-01-02 3.790965 -0.575836 0.731849 -1.050896
2 2000-01-03 4.994910 -2.211932 0.825693 -1.890958
3 2000-01-04 5.541881 0.112860 -0.357612 -2.818091
4 2000-01-05 5.767437 0.372435 -2.124310 -2.179938
... ... ... ... ... ...
995 2002-09-22 -27.517641 14.537824 -33.377617 -42.739328
996 2002-09-23 -29.672076 14.115574 -33.633798 -44.358625
997 2002-09-24 -30.274690 12.876268 -32.796361 -44.547047
998 2002-09-25 -29.809977 12.402727 -33.746257 -45.242380
999 2002-09-26 -29.891825 12.262031 -34.786199 -45.565377

1000 rows × 5 columns

Excel形式#

Series、DataFrameの to_excel() メソッドによってExcel形式での書き込みが、pandasの read_excel() 関数によってExcel形式データの読み込みができます。それぞれさまざまな引数が存在しますが、ここでは主要なもののみを紹介します。

DataFrame.to_excel(excel_writer, sheet_name='Sheet1') (詳細は公式ページ

  • excel_writer : 書き出し先のファイルパス( str

  • sheet_name : 書き出し先シートを設定( str

pandas.read_excel(io, sheet_name=0) (詳細は公式ページ

  • io : 読み込み対象のExcelファイルパス( str

  • sheet_name : インデックスとしたカラムを設定( strint など、 list での設定が可能)

# excel形式でのデータ書き込み
df.to_excel("foo.xlsx", sheet_name="sheet1")

# excel形式データの読み込み
display(pd.read_excel("foo.xlsx", "sheet1", index_col=None, na_values=["NA"]))
Unnamed: 0 A B C D
0 2000-01-01 1.943932 -0.208172 0.173399 -0.877959
1 2000-01-02 3.790965 -0.575836 0.731849 -1.050896
2 2000-01-03 4.994910 -2.211932 0.825693 -1.890958
3 2000-01-04 5.541881 0.112860 -0.357612 -2.818091
4 2000-01-05 5.767437 0.372435 -2.124310 -2.179938
... ... ... ... ... ...
995 2002-09-22 -27.517641 14.537824 -33.377617 -42.739328
996 2002-09-23 -29.672076 14.115574 -33.633798 -44.358625
997 2002-09-24 -30.274690 12.876268 -32.796361 -44.547047
998 2002-09-25 -29.809977 12.402727 -33.746257 -45.242380
999 2002-09-26 -29.891825 12.262031 -34.786199 -45.565377

1000 rows × 5 columns

小括#

本稿ではデータ分析で頻出のpandasの基本操作について、公式チュートリアルをベースに紹介しました。pandasにはここでは紹介しきれなかったさまざまな便利機能がまだまだ存在します。データを弄る際、まずはpandasの機能でどうにかならないか検索してみることをお勧めします。

参考文献#