ガバキックの将来を予測する
こんにちは、Quarkです。
突然ですが、ガバキックの将来って気になりませんか?
ガバキックに限らずですが、これ以上音源が伸びない時、「この音源に続きがあれば・・・クソッ!」ってなる時、あると思います。
この続き、予測できるんじゃないかなと思ったのでやってみました。
データを用意する
まずはデータが必要です。データは、私が以前オーディオで書き出して、以降続きのないガバキックを使います。
音はこんな感じです。
Pythonで音声ファイルを読み込み、数値の配列に変換します。
import wave
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
gabbakick = wave.open('gabbakick test.wav','r')
buf = gabbakick.readframes(gabbakick.getnframes())
data = np.frombuffer(buf, dtype='int16')
with mpl.rc_context():
mpl.rc('figure', figsize=(20, 5))
plt.plot(data)
plt.title('ガバキック')
波形を表示します。これの将来を予測します。
音源の続きのことを「将来」と言っているのは、音の波形も周期性があり、時系列予測と同じ形で予測できるからです。
学習させる
予測するにあたって用いるデータ箇所ですが、下記画像の水色+黄色の部分を用いて、赤の部分を予測したいと思います。
予測・学習には、LightGBMを使います。くわしくはGistにコードをアップしているので、気になる方は見てみてください。
データは、自己回帰的なことをさせるためにガバキックデータ配列のt列目に対して、-1t~-5000tまでのラグを取得し、追加します。
import pandas as pd
df = pd.DataFrame(data)[15000:].reset_index(drop=True)
#5000回ほどずらしていく
def columns_shift(df, shift_number):
df_list = []
df_list.append(df)
for i in range(1, shift_number + 1):
shift_column_name = int('-' + str(i))
df_list.append(df.shift(i).rename(columns={0:shift_column_name}))
return pd.concat([df_list[d] for d in range(len(df_list))], axis=1)
df_1 = columns_shift(df, 5000)
df_2 = df_1.dropna().reset_index(drop=True)
画像の0列目データがtです。
まずは、精度を確認・学習させるために、水色部分のデータを用いて、黄色部分のデータを予測します。
import lightgbm as lgb
y = 0 #目的変数
x = df_2.drop(0, axis=1).columns #説明変数
#時系列データなので、一旦テストでindex 10000~以降を予測して、精度をチェックする
train_x = df_2[x][:10000]
train_y = df_2[y][:10000]
valid_x = df_2[x][10000:]
valid_y = df_2[y][10000:]
lgb_train = lgb.Dataset(train_x, train_y)
lgb_valid = lgb.Dataset(valid_x, valid_y)
params = {
'n_jobs': -1,
'max_depth': 7,
'task':'train',
'boosting_type':'gbdt',
'metric':'rmse',
'learning_rate': 0.01,
'feature_fraction': 0.8,
'bagging_fraction': 0.8,
'objective': 'regression_l1'
}
model = lgb.train(params, lgb_train, num_boost_round=4000, valid_sets=[lgb_train, lgb_valid], early_stopping_rounds=100, verbose_eval=100)
test_pred_y = model.predict(valid_x)
赤線が学習させて、予測した結果です。ぱっと見、結構合ってますね。
精度は、R2_scoreで0.993,RMSEで1561.01です。とても良いと思います。
小ネタですが、今回の波形は、周期的に[-2t,-4040t,-2020t,-4042t,-1t,-4044t]あたりが、予測精度の向上に貢献しているみたいですね。このあたりは、フーリエ変換の際の高周波成分と結び付けられそうですね。
予測する
学習が終了したので、将来の波形を予測します。
tに対して-1t~-5000tのラグを用いているので、一気に波形の予測はできません。なので、流れとしては
次の波形1つ分を予測する→予測結果を-1tとして用いる→その次の波形1つを予測する→予測結果を-1tとして用いる→繰り返し
な形です。
def gabbakick_predict(predict_df, length):
from tqdm import tqdm
df_array = df[::-1].T.values[0]
for i in tqdm(range(length)):
predict_array = df_array[:5000].reshape(-1, 5000)
predict_y = model.predict(predict_array)[0]
df_array = np.insert(df_array, 0, predict_y) #df_arrayを上書き
return df_array
predict_result = gabbakick_predict(df, 20000) #20000先まで、予測・-1tとして結合を繰り返す
結果
赤線の部分がLightGBMを用いて、ガバキックの将来を予測した部分です。
なんと、このガバキックの将来は若干減衰していくんですね!なるほど!(厳密にはすべての-1~-5000tが予測値で代替される以降の正確性はわからないです)
とりあえず、ガバキックの将来が予測できたので、書き出して聴いてみようと思います。
おお~違和感ないですね、ちょっと途中で「ジリッ」とした音が聞こえますが、これが逆にいい味を出しているかも。
今回はガバキックで行いましたが、割といろんな音に使えるかもしれないですね、これは。
ああ~!予測の音ォ~!!