pandasで行・列の差分・変化率を取得するdiff, pct_change

pandas.DataFrame, pandas.Seriesの行または列の差分・変化率を取得するにはdiff(), pct_change()メソッドを使います。例えば一行前のデータとの差分・変化率を取得したりできます。

pandas.DataFrame.diff — pandas 0.23.3 documentation pandas.Series.diff — pandas 0.23.3 documentation pandas.DataFrame.pct_change — pandas 0.23.3 documentation pandas.Series.pct_change — pandas 0.23.3 documentation

ここでは以下の内容について説明します。

diff()の使い方 比較する値との差: 引数periods 行 or 列を指定: 引数axis pandas.Seriesに対するdiff()

pct_change()の使い方 比較する値との差: 引数periods 行 or 列を指定: 引数axis pandas.Seriesに対するpct_change()

欠損値NaNの処理 時系列データに対する差分・変化率 時系列データにdiff(), pct_change()をそのまま使う pct_change()の引数freqを指定して変化率取得 shift()でずらして差分取得

diff()の使い方

以下のpandas.DataFrameを例とします。

import pandas as pd

df = pd.DataFrame({'a': range(1, 6),
                   'b': [x**2 for x in range(1, 6)],
                   'c': [x**3 for x in range(1, 6)]})

print(df)
#    a   b    c
# 0  1   1    1
# 1  2   4    8
# 2  3   9   27
# 3  4  16   64
# 4  5  25  125

デフォルトでは1行前の値との差分が算出される。

print(df.diff())
#      a    b     c
# 0  NaN  NaN   NaN
# 1  1.0  3.0   7.0
# 2  1.0  5.0  19.0
# 3  1.0  7.0  37.0
# 4  1.0  9.0  61.0

比較する値との差: 引数periods

比較する値との差は第一引数periodsで指定します。デフォルトは1で1行前。

print(df.diff(2))
#      a     b     c
# 0  NaN   NaN   NaN
# 1  NaN   NaN   NaN
# 2  2.0   8.0  26.0
# 3  2.0  12.0  56.0
# 4  2.0  16.0  98.0

負の値も指定可能。

print(df.diff(-1))
#      a    b     c
# 0 -1.0 -3.0  -7.0
# 1 -1.0 -5.0 -19.0
# 2 -1.0 -7.0 -37.0
# 3 -1.0 -9.0 -61.0
# 4  NaN  NaN   NaN

行 or 列を指定: 引数axis

引数axis=1とすると列ごとの差分が算出される。

print(df.diff(axis=1))
#     a     b      c
# 0 NaN   0.0    0.0
# 1 NaN   2.0    4.0
# 2 NaN   6.0   18.0
# 3 NaN  12.0   48.0
# 4 NaN  20.0  100.0

print(df.diff(-1, axis=1))
#       a      b   c
# 0   0.0    0.0 NaN
# 1  -2.0   -4.0 NaN
# 2  -6.0  -18.0 NaN
# 3 -12.0  -48.0 NaN
# 4 -20.0 -100.0 NaN

pandas.Seriesに対するdiff()

pandas.Seriesに対するdiff()メソッドも同様。引数も同じ。

df['b_diff'] = df['b'].diff(-1)
print(df)
#    a   b    c  b_diff
# 0  1   1    1    -3.0
# 1  2   4    8    -5.0
# 2  3   9   27    -7.0
# 3  4  16   64    -9.0
# 4  5  25  125     NaN

pct_change()の使い方

pct_change()の使い方もdiff()とほぼ同じ。 diff()がA - Bで差分を算出するのに対し、pct_change()は(A - B) / Bで変化率を算出します。 以下のpandas.DataFrameを例とします。

import pandas as pd

df = pd.DataFrame({'a': range(1, 6),
                   'b': [x**2 for x in range(1, 6)],
                   'c': [x**3 for x in range(1, 6)]})

print(df)
#    a   b    c
# 0  1   1    1
# 1  2   4    8
# 2  3   9   27
# 3  4  16   64
# 4  5  25  125

デフォルトでは1行前の値との変化率が算出される。

print(df.pct_change())
#           a         b         c
# 0       NaN       NaN       NaN
# 1  1.000000  3.000000  7.000000
# 2  0.500000  1.250000  2.375000
# 3  0.333333  0.777778  1.370370
# 4  0.250000  0.562500  0.953125

比較する値との差: 引数periods

比較する値との差は第一引数periodsで指定します。デフォルトは1で1行前。

print(df.pct_change(2))
#           a         b         c
# 0       NaN       NaN       NaN
# 1       NaN       NaN       NaN
# 2  2.000000  8.000000  26.00000
# 3  1.000000  3.000000   7.00000
# 4  0.666667  1.777778   3.62963

負の値も指定可能。

print(df.pct_change(-1))
#           a         b         c
# 0 -0.500000 -0.750000 -0.875000
# 1 -0.333333 -0.555556 -0.703704
# 2 -0.250000 -0.437500 -0.578125
# 3 -0.200000 -0.360000 -0.488000
# 4       NaN       NaN       NaN

行 or 列を指定: 引数axis

引数axis=1とすると列ごとの変化率が算出される。

print(df.pct_change(axis=1))
#     a    b    c
# 0 NaN  0.0  0.0
# 1 NaN  1.0  1.0
# 2 NaN  2.0  2.0
# 3 NaN  3.0  3.0
# 4 NaN  4.0  4.0

print(df.pct_change(-1, axis=1))
#           a         b   c
# 0  0.000000  0.000000 NaN
# 1 -0.500000 -0.500000 NaN
# 2 -0.666667 -0.666667 NaN
# 3 -0.750000 -0.750000 NaN
# 4 -0.800000 -0.800000 NaN

pandas.Seriesに対するpct_cahnge()

pandas.Seriesに対するpct_change()メソッドも同様。引数も同じ。

df['b_pct_change'] = df['b'].pct_change(-1)
print(df)
#    a   b    c  b_pct_change
# 0  1   1    1     -0.750000
# 1  2   4    8     -0.555556
# 2  3   9   27     -0.437500
# 3  4  16   64     -0.360000
# 4  5  25  125           NaN

欠損値NaNの処理

diff()もpct_change()も結果に欠損値NaNが生じる。 欠損値NaNを削除したり穴埋めしたりするにはdropna(), fillna()を使います。

print(df.diff(2).dropna())
#      a     b     c
# 2  2.0   8.0  26.0
# 3  2.0  12.0  56.0
# 4  2.0  16.0  98.0

print(df.diff(2).fillna(0))
#      a     b     c
# 0  0.0   0.0   0.0
# 1  0.0   0.0   0.0
# 2  2.0   8.0  26.0
# 3  2.0  12.0  56.0
# 4  2.0  16.0  98.0

print(df.diff(2).fillna(method='bfill'))
#      a     b     c
# 0  2.0   8.0  26.0
# 1  2.0   8.0  26.0
# 2  2.0   8.0  26.0
# 3  2.0  12.0  56.0
# 4  2.0  16.0  98.0

pct_change()でも同じ。

print(df.pct_change(2).dropna())
#           a         b         c
# 2  2.000000  8.000000  26.00000
# 3  1.000000  3.000000   7.00000
# 4  0.666667  1.777778   3.62963

print(df.pct_change(2).fillna(0))
#           a         b         c
# 0  0.000000  0.000000   0.00000
# 1  0.000000  0.000000   0.00000
# 2  2.000000  8.000000  26.00000
# 3  1.000000  3.000000   7.00000
# 4  0.666667  1.777778   3.62963

print(df.pct_change(2).fillna(method='bfill'))
#           a         b         c
# 0  2.000000  8.000000  26.00000
# 1  2.000000  8.000000  26.00000
# 2  2.000000  8.000000  26.00000
# 3  1.000000  3.000000   7.00000
# 4  0.666667  1.777778   3.62963

dropna(), fillna()についての詳細は以下の記事を参照。

時系列データに対する差分・変化率

時系列データに対してもdiff(), pct_change()をそのまま使えるが、指定した日時ぶん離れたデータとの差分・変化率を取得することも可能。 以下の時系列データを例とします。

import pandas as pd

df = pd.DataFrame({'value': range(1, 16, 2)},
                  index=pd.date_range('2018-01-01', '2018-01-15', freq='2D'))

print(df)
#             value
# 2018-01-01      1
# 2018-01-03      3
# 2018-01-05      5
# 2018-01-07      7
# 2018-01-09      9
# 2018-01-11     11
# 2018-01-13     13
# 2018-01-15     15

diff(), pct_change()をそのまま使う

まずはdiff(), pct_change()を通常のデータと同じように使う例。行単位での差分・変化率を取得できます。 diff() デフォルトでは一つ上の行との差分が取得できます。第一引数periodsを指定すると比較する行との差を指定可能。

print(df.diff())
#             value
# 2018-01-01    NaN
# 2018-01-03    2.0
# 2018-01-05    2.0
# 2018-01-07    2.0
# 2018-01-09    2.0
# 2018-01-11    2.0
# 2018-01-13    2.0
# 2018-01-15    2.0

print(df.diff(2))
#             value
# 2018-01-01    NaN
# 2018-01-03    NaN
# 2018-01-05    4.0
# 2018-01-07    4.0
# 2018-01-09    4.0
# 2018-01-11    4.0
# 2018-01-13    4.0
# 2018-01-15    4.0

pct_change() pct_change()もdiff()と同様。

print(df.pct_change())
#                value
# 2018-01-01       NaN
# 2018-01-03  2.000000
# 2018-01-05  0.666667
# 2018-01-07  0.400000
# 2018-01-09  0.285714
# 2018-01-11  0.222222
# 2018-01-13  0.181818
# 2018-01-15  0.153846

print(df.pct_change(2))
#                value
# 2018-01-01       NaN
# 2018-01-03       NaN
# 2018-01-05  4.000000
# 2018-01-07  1.333333
# 2018-01-09  0.800000
# 2018-01-11  0.571429
# 2018-01-13  0.444444
# 2018-01-15  0.363636

pct_change()の引数freqを指定して変化率取得

pct_change()には引数freqを指定できます。D(日)、H(時)などの頻度コードを指定すると、インデックスを任意の日時ぶんずらすことができます。

以下の例では2行前のデータではなく2日前のデータとの変化率となります。

print(df.pct_change(freq='2D'))
#                value
# 2018-01-01       NaN
# 2018-01-03  2.000000
# 2018-01-05  0.666667
# 2018-01-07  0.400000
# 2018-01-09  0.285714
# 2018-01-11  0.222222
# 2018-01-13  0.181818
# 2018-01-15  0.153846

元データに無い日時のデータを指定すると欠損値NaNになる。

print(df.pct_change(freq='D'))
#             value
# 2018-01-01    NaN
# 2018-01-03    NaN
# 2018-01-05    NaN
# 2018-01-07    NaN
# 2018-01-09    NaN
# 2018-01-11    NaN
# 2018-01-13    NaN
# 2018-01-15    NaN

shift()でずらして差分取得

diff()には引数freqがないので、代わりにshift()を使います。 shift()の引数freqにD(日)、H(時)などの頻度コードを指定すると、インデックスを任意の日時ぶんずらすことができます。

print(df.shift(freq='2D'))
#             value
# 2018-01-03      1
# 2018-01-05      3
# 2018-01-07      5
# 2018-01-09      7
# 2018-01-11      9
# 2018-01-13     11
# 2018-01-15     13
# 2018-01-17     15

これを元データから引くと、指定した日時ぶん離れたデータとの差分を取得可能。以下の例では2行前のデータではなく2日前のデータとの差分となります。

print(df - df.shift(freq='2D'))
#             value
# 2018-01-01    NaN
# 2018-01-03    2.0
# 2018-01-05    2.0
# 2018-01-07    2.0
# 2018-01-09    2.0
# 2018-01-11    2.0
# 2018-01-13    2.0
# 2018-01-15    2.0
# 2018-01-17    NaN

元データに無い日時のデータを引くと欠損値NaNになる。以下の例のように隔日のデータしかないのに1日前のデータとの差分を取ろうとするとすべてNaNになる。

print(df - df.shift(freq='D'))
#             value
# 2018-01-01    NaN
# 2018-01-02    NaN
# 2018-01-03    NaN
# 2018-01-04    NaN
# 2018-01-05    NaN
# 2018-01-06    NaN
# 2018-01-07    NaN
# 2018-01-08    NaN
# 2018-01-09    NaN
# 2018-01-10    NaN
# 2018-01-11    NaN
# 2018-01-12    NaN
# 2018-01-13    NaN
# 2018-01-14    NaN
# 2018-01-15    NaN
# 2018-01-16    NaN

シェア

関連カテゴリー

Python pandas 時系列データ

pandasで窓関数を適用するrollingを使って移動平均などを算出 pandas.DataFrame, Seriesを時系列データとして処理 pandasの時系列データにおける頻度(引数freq)の指定方法 pandasで時系列データをリサンプリングするresample, asfreq pandasで時系列データのOHLC(四本値)を算出・ダウンサンプリング pandas, Matplotlib(mpl_finance)でローソク足チャートを作成 pandasの時系列データのタイムゾーンを処理(tz_convert, tz_localize) pandasでデータを行・列(縦・横)方向にずらすshift pandasで時系列データの曜日や月、四半期、年ごとの合計や平均を算出 pandasで文字列にスライスを適用して任意の位置・長さの部分を抽出 pandasで要素、行、列に関数を適用するmap, applymap, apply pandasのバージョンを確認(pd.show_versions) pandasで特定の条件を満たす要素数をカウント(全体、行・列ごと) pandasのインデックス参照で行・列を選択し取得 PythonでRESAS APIを使ってデータをダウンロード

Last Updated: 6/26/2019, 10:34:03 PM