【Python】データ解析に欠かせない!Pandasの使い方⑤

こんにちは、unogram管理人のうのちゅ〜です。

今回は、Pythonによるデータ解析に欠かせないライブラリPandasの使い方の解説第5回です。Pandasは、機械学習に必要なデータの前処理や加工、統計量の算出にも便利で、Pythonユーザならぜひとも使いこなせるようにしておきたいライブラリです。

Pandas公式の10 minutes to pandasを参考に進めている本シリーズ、第1回【Python】データ解析に欠かせない!Pandasの使い方①からご覧いただくとスムーズに理解できるかと思います。

今回は主にPandasのDataFrameオブジェクトにおける「時系列データの扱い、カテゴリー、ファイル入出力」の基礎について解説します。5回に渡る10 minutes to pandasの解説も今回が最終回です!

それでは見ていきましょう!



Pandasの使い方⑤

pandasとnumpyをインポートします。

import pandas as pd
import numpy as np

時系列データの作成 pd.date_range

頻度(freq)を指定して時系列データ(DatetimeIndex)を生成します。

次の例では、2020/11/1 00:00:00から、1秒置きに100個の時系列データを生成しています。freq=’S’は「秒」を指定する頻度コードです。

rng = pd.date_range('11/1/2020', periods=100, freq='S')
rng
# DatetimeIndex(['2020-11-01 00:00:00', '2020-11-01 00:00:01',
#               '2020-11-01 00:00:02', '2020-11-01 00:00:03',
#               '2020-11-01 00:00:04', '2020-11-01 00:00:05',
# (中略)
#               '2020-11-01 00:01:34', '2020-11-01 00:01:35',
#               '2020-11-01 00:01:36', '2020-11-01 00:01:37',
#               '2020-11-01 00:01:38', '2020-11-01 00:01:39'],
#               dtype='datetime64[ns]', freq='S')              

indexに先程生成した時系列データを設定し、各データに対して0以上500未満の整数乱数の値をもつSeriesオブジェクトを生成します。

ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
ts
# 2020-11-01 00:00:00     12
# 2020-11-01 00:00:01    498
# 2020-11-01 00:00:02    360
# 2020-11-01 00:00:03    224
# 2020-11-01 00:00:04    136
#                       ... 
# 2020-11-01 00:01:35     79
# 2020-11-01 00:01:36    295
# 2020-11-01 00:01:37     60
# 2020-11-01 00:01:38     43
# 2020-11-01 00:01:39     73
# Freq: S, Length: 100, dtype: int64

リサンプリング resample()

先程生成したSeriesオブジェクトtsを10秒置きにリサンプリングし、sum()メソッドを適用します。

ts.resample('10s').sum()
# 2020-11-01 00:00:00    2491
# 2020-11-01 00:00:10    3535
# 2020-11-01 00:00:20    2516
# 2020-11-01 00:00:30    2830
# 2020-11-01 00:00:40    3313
# 2020-11-01 00:00:50    2137
# 2020-11-01 00:01:00    1974
# 2020-11-01 00:01:10    1930
# 2020-11-01 00:01:20    3420
# 2020-11-01 00:01:30    1479
# Freq: 10S, dtype: int64

タイムゾーンの設定・変更 tz_localize, tz_convert

tz_localize()メソッドでタイムゾーンを設定します。下の例では協定世界時(UTC, Coordinated Universal Time)に設定しています。

ts_utc = ts.tz_localize('UTC')
ts_utc
# 2020-11-01 00:00:00+00:00     12
# 2020-11-01 00:00:01+00:00    498
# 2020-11-01 00:00:02+00:00    360
# 2020-11-01 00:00:03+00:00    224
# 2020-11-01 00:00:04+00:00    136
#                             ... 
# 2020-11-01 00:01:35+00:00     79
# 2020-11-01 00:01:36+00:00    295
# 2020-11-01 00:01:37+00:00     60
# 2020-11-01 00:01:38+00:00     43
# 2020-11-01 00:01:39+00:00     73
# Freq: S, Length: 100, dtype: int64

tz_convert()メソッドでタイムゾーンを変換します。タイムゾーンを’Asia/Tokyo’に設定すると、日本標準時 (JST)に変換されるため、UTC+09:00となります。

ts_utc.tz_convert('Asia/Tokyo')
# 2020-11-01 09:00:00+09:00     12
# 2020-11-01 09:00:01+09:00    498
# 2020-11-01 09:00:02+09:00    360
# 2020-11-01 09:00:03+09:00    224
# 2020-11-01 09:00:04+09:00    136
#                             ... 
# 2020-11-01 09:01:35+09:00     79
# 2020-11-01 09:01:36+09:00    295
# 2020-11-01 09:01:37+09:00     60
# 2020-11-01 09:01:38+09:00     43
# 2020-11-01 09:01:39+09:00     73
# Freq: S, Length: 100, dtype: int64

カテゴリー cat.categories, cat.set_categories

DataFrameオブジェクトにカテゴリーを設定し、ラベル付けやソート、グルーピングを行うことができます。

# DataFrameを生成します。
df = pd.DataFrame({"id": [1, 2, 3, 4, 5, 6],
                       "raw_grade": ['a', 'b', 'b', 'a', 'a', 'e']})
df

新しく’grade’列を定義し、dtypeを’category’に設定します。この時点ではデータは’raw_grade’列と同一です。

df["grade"] = df["raw_grade"].astype("category")
df

一見’raw_grade’列と’grade’列は同じものに見えますが、’grade’列はdtypeが’category’、’raw_grade’列はdtypeが’object’となっていることがわかります。

df['grade']
# 0    a
# 1    b
# 2    b
# 3    a
# 4    a
# 5    e
# Name: grade, dtype: category
# Categories (3, object): [a, b, e]

df['raw_grade']
# 0    a
# 1    b
# 2    b
# 3    a
# 4    a
# 5    e
# Name: raw_grade, dtype: object

.cat.categoriesでカテゴリーをより意味のある文字列でリネームします。

df["grade"].cat.categories = ["very good", "good", "very bad"]
df

cat.set_categoriesでさらにカテゴリーを追加することもできます。出力結果に変化はありません。

df["grade"] = df["grade"].cat.set_categories(["very bad", "bad", "medium",
                                                  "good", "very good"])
df

カテゴリーを設定すると、辞書式ではなく、categoryに沿ったソートを行うことができます。

df.sort_values(by="grade")

dtype=’category’の列でグルーピングすると、空のカテゴリーも表示されます。

df.groupby("grade").size()
# grade
# very bad     1
# bad          0
# medium       0
# good         2
# very good    3
# dtype: int64



Seriesオブジェクトのプロット

ランダムなデータからなるSeriesオブジェクトの累積和をプロットします。

ts = pd.Series(np.random.randn(1000),
                   index=pd.date_range('11/1/2020', periods=1000))
ts = ts.cumsum()
ts.plot()

DataFrameオブジェクトのプロット

ランダムなデータからなるDataFrameオブジェクトの累積和をプロットします。DataFrameオブジェクトのプロットでは、各列のデータを一挙にプロットできます。

df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index,
                      columns=['A', 'B', 'C', 'D'])
df = df.cumsum()
df.plot()
plt.legend(loc='best') # 凡例を適当な位置に表示します。凡例は'columns'のラベルとなります。

Pythonにおける様々なプロット方法については、【具体例で説明】Pythonでなるべく簡単にプロットする方法も参考にしてみてください。

CSVの読み書き to_csv, read_csv

to_csv()メソッドでDataFrameオブジェクトをCSVファイルに書き込み、read_csv()メソッドでCSVファイルから読み込みます。

# 書き出し
df.to_csv('foo.csv')

# 読み込み
pd.read_csv('foo.csv')

HDF5の読み書き to_hdf, read_hdf

HDF5(Hierarchical Data Formatのバージョン5)は、階層化されたデータのファイル形式で、CSV同様データの保存・読み書きに使用されます。

書き出しを行うto_hdf()メソッド、読み込みを行うread_hdf()では、共に第一引数にファイル名、第二引数にkeyを指定する必要があります。

# 書き出し
df.to_hdf('foo.h5', 'df1')

# 読み込み
pd.read_hdf('foo.h5', 'df1')

エクセルファイル(.xlsx)の読み書き

to_excel()でエクセルファイル(.xlsx)に書き出し、read_excel()で読み込みます。引数によってシート名の指定などを行うことができます。

# 書き出し
df.to_excel('foo.xlsx')
# df.to_excel('foo.xlsx', sheet_name='Sheet1') # シート名を指定することもできます。

# 読み込み
pd.read_excel('foo.xlsx')



まとめ

今回は、Pythonによるデータ解析に欠かせないライブラリPandasの使い方を解説しました。第5回として、主に時系列データの扱い、カテゴリー、各種ファイル入出力の基礎について解説しました。

10 minutes to pandasを参考にしたPandas入門シリーズも最終回でした。広く浅くではありますが、Pandasでどのようなことができるのかをつかむことができたのではないかと思います。

より詳しく学びたいという方は下記の参考書などを使ってさらに学習してみてください。

参考書学習は…

Pandasはデータ解析需要の増加に伴い、多数の専門書が刊行されています。必要に応じて書籍を通して学ぶこともデータ解析力の向上には欠かせません。

numpyやpandasを含めて、データサイエンスに必要なライブラリを俯瞰的に詳しく学習したい方は次の書籍がおすすめです。

参考

10 minutes to pandas