観測データには欠損値や異常値がしばしば含まれる。
幸い、AMeDASのような観測体制がしっかりしているデータにこれらが含まれることはそう多くないが(一日平均のデータなので数点欠損があっても他で補える、という理由もある)欠損値・異常値の処理はデータ解析で労力を使うプロセスの一つである。
ここでは、1978年のAMeDASデータ(欠損があるので...)を用いて、欠損値処理について説明する。
isnull()
: 各要素について、欠損値(NaN)であれば True を、なければ False を返す。any()
: 要素の中にTrueが一つでもあれば True を返す。 import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
#from pandas.plotting import register_matplotlib_converters
#%register_matplotlib_converters()
file = "../../DB_2020/data/Kyoto/Kyoto_1978.csv"
df = pd.read_csv(file,encoding = "shift-jis",header=2,index_col=0,parse_dates=[0])
df = df.iloc[2:,:]
temp = df['平均気温(℃)']
### isnullを適用すると...
print(temp.isnull().head())
temp_v = temp.values
print(type(temp_v))
### 一つでもTrue(Nan)があるか?
print(temp.isnull().any())
あった!(あまり嬉しくないが)。ちなみにこの部分だけ抜き出してきて、何月何日のデータが欠損なのか調べてみる。
print(temp[temp.isnull()])
幸いなことにpandasでは描画・統計処理において欠損値を考慮した結果・図
を示してくれる。
ただし、スペクトル解析など、連続データを必要とする場合には穴埋めが必要である。 手法としては線形補間やスプライン補間が用いられる。
(オプションの例)
method
: linear
:線形補間(デフォルト)、index
:インデックスの値を考慮した線形補間、 spline
: スプライン補間(この場合は同時にorder
(次数)を指定する)
axis
: 補間を行う軸。デフォルトは 0
# 補間
temp_int = temp.interpolate(method='index')
temp_intS = temp.interpolate(method='spline',order=3) #スプライン補間
# データが埋まったか確認
print(temp_int.isnull().any())
これで無事に欠損データがなくなった。最後に補間する前と後のデータを図示して比べてみよう。
dst = "1978-05-15"; den = "1978-07-15"
# 図示
fig = plt.figure(figsize=(10,4))
ax = fig.add_subplot(111)
# 補間後
ax.plot(temp_intS[dst:den],label='Interpolated (Spline)')
ax.plot(temp_int[dst:den],label='Interpolated (Linear)')
# 補間前
ax.plot(temp[dst:den],label='Original')
ax.set_title('Temperature')
ax.set_xlabel('Date')
ax.set_ylabel('Temperature')
ax.legend()
# 図を表示
plt.show()
一方、異常値の除去については決まったやり方は存在せず、データの質や状況に応じて適切な手法を用いるしかない(今でも気象庁での品質管理では最後は人が目で見てチェックしているようである)。データセットによっては、品質管理情報が付与されていることもある(ここで用いているAMeDASデータでも、整数値として与えられている)。
一から異常値を除去する場合、手法はいろいろあるが、個人的にはメディアンフィルターが気に入っている。これはデータをある期間に区切ってそれぞれでメディアン(中央値)を求め、そこから大きく外れた値(標準偏差の3倍とか)を欠損とみなすものである(この作業を収束するまで(外れた値が無くなるまで)繰り返すこともある)。ちなみに、京大のMUレーダーの品質管理でもこの手法がベースになっていた。