PythonモジュールPandasで読み込んだ信号データの近似直線・曲線をScikit-learnで計算する方法についてソースコード付きでまとめました。
【例1】近似直線を回帰分析で計算
Pandasで読み込んだ信号データ(CSV)を読み込み、近似直線を回帰分析で計算します。
種別 | 回帰分析の詳細、読み込んだCSVデータはこちら |
---|---|
1 | 【単回帰分析】原理と計算式・相関係数・決定係数・例題 |
2 | 【Scikit-learn】単回帰分析 |
CSV | current.csv |
サンプルコード
# -*- coding: utf-8 -*- import os import pandas as pd import matplotlib import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit import ntpath from sklearn import linear_model import joblib # 読み込むCSVファイルのパス csv_path = "C:/prog/python/auto/current.csv" save_path = "C:/prog/python/" # 空のデータフレームを作成 df = pd.DataFrame({}) # CSVファイルのロードし、データフレームへ格納 df = pd.read_csv(csv_path, encoding="UTF-8", skiprows=0) # 電流値の列データを取り出し Its = df.loc[:, "current"] # 経過時間の列データを取り出し times = df.loc[:, "time"] # 線形回帰モデル clf = linear_model.LinearRegression() # 説明変数xに "x1"のデータを使用 x = np.array([times]).T # 目的変数yに "x2"のデータを使用 y = Its.values # 予測モデルを作成(単回帰) clf.fit(x, y) # パラメータ(回帰係数、切片)を抽出 [a] = clf.coef_ b = clf.intercept_ # パラメータの表示 print("回帰係数:", a) print("切片:", b) print("決定係数:", clf.score(x, y)) """ 回帰係数: 0.27799504539192565 切片: 147.94961709941853 決定係数: 0.3892789344510325 """ # 学習結果の出力 joblib.dump(clf, 'C:\prog\python\scikit\clf.learn') # 保存先パスが存在しなければ作成 if not os.path.exists(save_path): os.mkdir(save_path) # グラフ化 ax = plt.axes() plt.rcParams['font.family'] = 'Times New Roman' # 全体のフォント plt.rcParams['axes.linewidth'] = 1.0 # 軸の太さ # 電流値をプロット plt.plot(times, Its, lw=1, c="r", alpha=0.7, ms=2, label="I(t)") # 電流値をプロット plt.plot(times, times * a + b, lw=1, c="b", alpha=0.7, ms=2, label="Lr(t)") # グラフの保存 plt.legend(loc="best") # 凡例の表示(2:位置は第二象限) plt.xlabel('Time[msec]', fontsize=12) # x軸ラベル plt.ylabel('Current[A]', fontsize=12) # y軸ラベル plt.grid() # グリッドの表示 plt.legend(loc="best") # 凡例の表示 plt.savefig(save_path + "current.png") plt.clf()
また、Scipyのoptimize.leastsq(最小二乗法による近似)でも同じことができます。
# -*- coding: utf-8 -*- import os import pandas as pd import matplotlib import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit import ntpath from sklearn import linear_model import joblib from scipy import optimize # 1次式の近似関数 def approx_func1d(param, x, y): residual = y - (param[0] * x + param[1]) return residual # 決定係数R^2の計算 def calc_r2(x_data, y_data, y_predict): residuals = y_data - y_predict rss = np.sum(residuals**2) # residual sum of squares = rss tss = np.sum((y_data - np.mean(y_data)) ** 2) # total sum of squares = tss r2 = 1 - (rss / tss) return r2 param1 = [0, 0] # 読み込むCSVファイルのパス csv_path = "C:/prog/python/auto/current.csv" save_path = "C:/prog/python/auto/" # 空のデータフレームを作成 df = pd.DataFrame({}) # CSVファイルのロードし、データフレームへ格納 df = pd.read_csv(csv_path, encoding="UTF-8", skiprows=0) # 電流値の列データを取り出し Its = df.loc[:, "current"] # 経過時間の列データを取り出し times = df.loc[:, "time"] # 近似直線のパラメータを計算 lq = optimize.leastsq(approx_func1d, param1, args=(times, Its)) # 係数 a = lq[0][0] b = lq[0][1] # 近似直線 y_predict = times * a + b # 決定係数 r2 = calc_r2(times, Its, y_predict) # パラメータの表示 print("回帰係数:", a) print("切片:", b) print("決定係数:", r2) """ 回帰係数: 0.27799504539192565 切片: 147.94961709941853 決定係数: 0.3892789344510325 """ # 保存先パスが存在しなければ作成 if not os.path.exists(save_path): os.mkdir(save_path) # グラフ化 ax = plt.axes() plt.rcParams['font.family'] = 'Times New Roman' # 全体のフォント plt.rcParams['axes.linewidth'] = 1.0 # 軸の太さ # 電流値をプロット plt.plot(times, Its, lw=1, c="r", alpha=0.7, ms=2, label="I(t)") # 電流値をプロット plt.plot(times, y_predict, lw=1, c="b", alpha=0.7, ms=2, label="Lr(t)") # グラフの保存 plt.legend(loc="best") # 凡例の表示(2:位置は第二象限) plt.xlabel('Time[msec]', fontsize=12) # x軸ラベル plt.ylabel('Current[A]', fontsize=12) # y軸ラベル plt.grid() # グリッドの表示 plt.legend(loc="best") # 凡例の表示 plt.savefig(save_path + "current.png") plt.clf()
【例2】近似曲線を計算
Pandasで読み込んだ信号データ(CSV)を読み込み、近似曲線をScipyのoptimize.leastsq(最小二乗法による近似)で計算します。
2次の近似曲線
# -*- coding: utf-8 -*- import os import pandas as pd import matplotlib import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit import ntpath from sklearn import linear_model import joblib from scipy import optimize # 近似関数 def approx_func(param, x, y): y = param[0]*x**2 + param[1]*x + param[2] return y # 誤差関数 def residual_func(param, x, y): residual = y - approx_func(param, x, y) return residual # 決定係数R^2の計算 def calc_r2(x_data, y_data, y_predict): residuals = y_data - y_predict rss = np.sum(residuals**2) # residual sum of squares = rss tss = np.sum((y_data - np.mean(y_data)) ** 2) # total sum of squares = tss r2 = 1 - (rss / tss) return r2 # 開始時間~終了時間 (time_start, time_end) = (0, 580) # パラメータの初期値 param1 = [0, 0, 0] # 読み込むCSVファイルのパス csv_path = "C:/prog/python/auto/current.csv" # グラフ画像の保存先パス save_path = "C:/prog/python/auto/" # 空のデータフレームを作成 df = pd.DataFrame({}) # CSVファイルのロードし、データフレームへ格納 df = pd.read_csv(csv_path, encoding="UTF-8", skiprows=0) # 電流値の列データを取り出し Its = df.loc[:, "current"] # 経過時間の列データを取り出し times = df.loc[:, "time"] Its = Its[(times > time_start) & (times < time_end)] times = times[(times > time_start) & (times < time_end)] # 近似直線のパラメータを計算 lq = optimize.leastsq(residual_func, param1, args=(times, Its)) # 係数 (a1, a2, b) = (lq[0][0], lq[0][1], lq[0][2]) # 近似直線 y_predict = approx_func(lq[0], times, Its) # 決定係数 r2 = calc_r2(times, Its, y_predict) # パラメータの表示 print("回帰係数a1:", a1) print("回帰係数a2:", a2) print("切片:", b) print("決定係数:", r2) """ 回帰係数a1: -0.0011648819127047887 回帰係数a2: 1.0631165109915937 切片: 63.04535136871891 決定係数: 0.966288014400727 """ # 保存先パスが存在しなければ作成 if not os.path.exists(save_path): os.mkdir(save_path) # グラフ化 ax = plt.axes() plt.rcParams['font.family'] = 'Times New Roman' # 全体のフォント plt.rcParams['axes.linewidth'] = 1.0 # 軸の太さ # 電流値をプロット plt.plot(times, Its, lw=1, c="r", alpha=0.7, ms=2, label="I(t)") # 電流値をプロット plt.plot(times, y_predict, lw=1, c="b", alpha=0.7, ms=2, label="Lr(t)") # グラフの保存 plt.legend(loc="best") # 凡例の表示(2:位置は第二象限) plt.xlabel('Time[msec]', fontsize=12) # x軸ラベル plt.ylabel('Current[A]', fontsize=12) # y軸ラベル plt.grid() # グリッドの表示 plt.legend(loc="best") # 凡例の表示 plt.savefig(save_path + "current.png") plt.clf()
3次の近似曲線
# -*- coding: utf-8 -*- import os import pandas as pd import matplotlib import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit import ntpath from sklearn import linear_model import joblib from scipy import optimize # 近似関数 def approx_func(param, x, y): y = param[0] * x ** 3 + param[1] * x ** 2 + param[2] * x + param[3] return y def residual_func(param, x, y): residual = y - approx_func(param, x, y) return residual # 決定係数R^2の計算 def calc_r2(x_data, y_data, y_predict): residuals = y_data - y_predict rss = np.sum(residuals**2) # residual sum of squares = rss tss = np.sum((y_data - np.mean(y_data)) ** 2) # total sum of squares = tss r2 = 1 - (rss / tss) return r2 # 開始時間~終了時間 (time_start, time_end) = (0, 580) # パラメータの初期値 param1 = [0, 0, 0, 0] # 読み込むCSVファイルのパス csv_path = "C:/prog/python/auto/current.csv" # グラフ画像の保存先パス save_path = "C:/prog/python/auto/" # 空のデータフレームを作成 df = pd.DataFrame({}) # CSVファイルのロードし、データフレームへ格納 df = pd.read_csv(csv_path, encoding="UTF-8", skiprows=0) # 電流値の列データを取り出し Its = df.loc[:, "current"] # 経過時間の列データを取り出し times = df.loc[:, "time"] Its = Its[(times > time_start) & (times < time_end)] times = times[(times > time_start) & (times < time_end)] # 近似直線のパラメータを計算 lq = optimize.leastsq(residual_func, param1, args=(times, Its)) # 係数 (a1, a2, a3, b) = (lq[0][0], lq[0][1], lq[0][2], lq[0][3]) # 近似直線 y_predict = approx_func(lq[0], times, Its) # 決定係数 r2 = calc_r2(times, Its, y_predict) # パラメータの表示 print("回帰係数a1:", a1) print("回帰係数a2:", a2) print("回帰係数a3:", a3) print("切片:", b) print("決定係数:", r2) """ 回帰係数a1: 2.977212732750732e-06 回帰係数a2: -0.003755056988060013 回帰係数a3: 1.6641407583301977 切片: 33.97080210048596 決定係数: 0.989262775952743 """ # 保存先パスが存在しなければ作成 if not os.path.exists(save_path): os.mkdir(save_path) # グラフ化 ax = plt.axes() plt.rcParams['font.family'] = 'Times New Roman' # 全体のフォント plt.rcParams['axes.linewidth'] = 1.0 # 軸の太さ # 電流値をプロット plt.plot(times, Its, lw=1, c="r", alpha=0.7, ms=2, label="I(t)") # 電流値をプロット plt.plot(times, y_predict, lw=1, c="b", alpha=0.7, ms=2, label="Lr(t)") # グラフの保存 plt.legend(loc="best") # 凡例の表示(2:位置は第二象限) plt.xlabel('Time[msec]', fontsize=12) # x軸ラベル plt.ylabel('Current[A]', fontsize=12) # y軸ラベル plt.grid() # グリッドの表示 plt.legend(loc="best") # 凡例の表示 plt.savefig(save_path + "current.png") plt.clf()
対数関数で近似曲線
# -*- coding: utf-8 -*- import os import pandas as pd import matplotlib import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit import ntpath from sklearn import linear_model import joblib from scipy import optimize # 近似関数 def approx_func(param, x, y): y = param[0] * np.log(x) + param[1] return y # 誤差関数 def residual_func(param, x, y): residual = y - approx_func(param, x, y) return residual # 決定係数R^2の計算 def calc_r2(x_data, y_data, y_predict): residuals = y_data - y_predict rss = np.sum(residuals**2) # residual sum of squares = rss tss = np.sum((y_data - np.mean(y_data)) ** 2) # total sum of squares = tss r2 = 1 - (rss / tss) return r2 # 開始時間~終了時間(0~500ms) (time_start, time_end) = (0, 580) # パラメータの初期値 param1 = [0, 0, 0] # 読み込むCSVファイルのパス csv_path = "C:/prog/python/auto/current.csv" # グラフ画像の保存先パス save_path = "C:/prog/python/auto/" # 空のデータフレームを作成 df = pd.DataFrame({}) # CSVファイルのロードし、データフレームへ格納 df = pd.read_csv(csv_path, encoding="UTF-8", skiprows=0) # 電流値の列データを取り出し Its = df.loc[:, "current"] # 経過時間の列データを取り出し times = df.loc[:, "time"] # 指定した時間帯のデータを抽出 Its = Its[(times > time_start) & (times < time_end)] times = times[(times > time_start) & (times < time_end)] # 近似直線のパラメータを計算 lq = optimize.leastsq(residual_func, param1, args=(times, Its)) # 係数 (a1, a2, b) = (lq[0][0], lq[0][1], lq[0][2]) # 近似直線 y_predict = approx_func(lq[0], times, Its) # 決定係数 r2 = calc_r2(times, Its, y_predict) # パラメータの表示 print("回帰係数a1:", a1) print("回帰係数a2:", a2) print("切片:", b) print("決定係数:", r2) """ 回帰係数a1: 71.40748902896294 回帰係数a2: -142.30699362830808 切片: 0.0 決定係数: 0.9611290963985782 """ # 保存先パスが存在しなければ作成 if not os.path.exists(save_path): os.mkdir(save_path) # グラフ化 ax = plt.axes() plt.rcParams['font.family'] = 'Times New Roman' # 全体のフォント plt.rcParams['axes.linewidth'] = 1.0 # 軸の太さ # 電流値をプロット plt.plot(times, Its, lw=1, c="r", alpha=0.7, ms=2, label="I(t)") # 電流値をプロット plt.plot(times, y_predict, lw=1, c="b", alpha=0.7, ms=2, label="Lq(t)") # グラフの保存 plt.legend(loc="best") # 凡例の表示(2:位置は第二象限) plt.xlabel('Time[msec]', fontsize=12) # x軸ラベル plt.ylabel('Current[A]', fontsize=12) # y軸ラベル plt.grid() # グリッドの表示 plt.legend(loc="best") # 凡例の表示 plt.savefig(save_path + "current.png") plt.clf()
- | 関連記事 |
---|---|
1 | 【Python】Pandasで信号処理入門 |
2 | 【Pandas入門】データ分析のサンプル集 |
3 | 【Python入門】サンプル集・使い方 |
コメント