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_change()
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