ちょいめも

物理/Python/Cの雑記帳

フィッティング

pythonでフィッティングするときのためのめも。

コード
fitlin.py

"""
線形フィッティング
"""
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit


# fitting関数
def fit(x, a, b):
    return a * x + b


# データ入力
array_x = np.array([0, 1, 2, 3, 4, 5, 6])
array_y = np.array([0.2, 1.4, 2.2, 3.1, 4.5, 5.2, 5.8])

# paramはフィッティングパラメータ、covは共分散行列
param, cov = curve_fit(fit, array_x, array_y)
# 共分散のルートでフィッティングパラメータの誤差
error = np.sqrt(np.diag(cov))

# fitting係数出力
print("a:{:.6f} b:{:.6f}".format(param[0], param[1]))
print("sigma_a:{:.6f} sigma_b:{:.6f}".format(error[0], error[1]))

# fitting関数からデータ作成
array_y_fit = fit(array_x, param[0], param[1])

# グラフ描画
plt.plot(array_x, array_y)
plt.plot(array_x, array_y_fit)
plt.show()

・入力データ
lognormal_dat.csv

0.01,0.0001
0.1,0.017
1,0.24
2,0.2
3,0.13
4,0.09
5,0.06
6,0.04
7,0.03
8,0.03
9,0.02
10,0.01

fitlognorm.py

"""
対数正規分布をフィッティング
"""
import os
import sys

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy.optimize import curve_fit


# 対数正規分布
def lognormal(x, a, sigma, mu, c):
    return a * (1 / (np.sqrt(2 * np.pi * sigma**2) * x) * np.exp(-((np.log(x) - mu) ** 2) / (2 * sigma**2))) + c


if __name__ == "__main__":
    argvs = sys.argv
    argc = len(argvs)

    # エラー処理
    if argc != 2:
        print("引数1:対数正規分布データ")
        input("キーを何か押すと終了します。")
        sys.exit()

    # ファイル保存設定
    savedir = os.path.dirname(os.path.abspath(argvs[1]))
    filename, ext = os.path.splitext(os.path.basename(argvs[1]))

    # データ読み込み
    data = np.loadtxt(argvs[1], delimiter=",")
    pdf_x = data[:, 0]
    pdf_y = data[:, 1]

    # === 対数正規分布フィッティング ===
    # paramはフィッティングパラメータ、covは共分散行列
    param_ini = (1, 1, 1, 0)  # 初期値
    param, cov = curve_fit(lognormal, pdf_x, pdf_y, p0=param_ini)
    # 共分散のルートでフィッティングパラメータの不確かさ
    err = np.sqrt(np.diag(cov))

    # fitting係数出力
    print("・対数正規分布")
    print("a     : {:.6f} +- {:.6f}".format(param[0], err[0]))
    print("sigma : {:.6f} +- {:.6f}".format(param[1], err[1]))
    print("mu    : {:.6f} +- {:.6f}".format(param[2], err[2]))
    print("c     : {:.6f} +- {:.6f}".format(param[3], err[3]))
    print("\n")

    # fitting関数からデータ作成
    pdf_y_fit = lognormal(pdf_x, param[0], param[1], param[2], param[3])

    # フィッティングデータ保存
    # パラメータ
    name_pdf = np.array(["a", "sigma", "mu", "c", "a_sigma", "sigma_sigma", "mu_sigma", "c_sigma"])
    data_pdf = np.array([param[0], param[1], param[2], param[3], err[0], err[1], err[2], err[3]])
    data_pdf_df = pd.DataFrame([np.round(data_pdf, 6)])
    data_pdf_df.to_csv(savedir + "\\" + filename + "_pdf_fitting_param.csv", header=name_pdf, index=False)
    # フィッティングy
    name_pdf = np.array(["x", "fit_y"])
    data_pdf = np.vstack((pdf_x, pdf_y_fit)).T
    data_pdf_df = pd.DataFrame(np.round(data_pdf, 6))
    data_pdf_df.to_csv(savedir + "\\" + filename + "_pdf_fitting.csv", header=name_pdf, index=False)

    # === グラフ描画 ===
    plt.plot(pdf_x, pdf_y, "o", label="data")
    plt.plot(pdf_x, pdf_y_fit, label="fit")
    plt.title("log-normal PDF\n{0}".format(filename))
    plt.xlabel("x")
    plt.ylabel("PDF")
    plt.grid(which="major", axis="x", color="gray", alpha=0.8, linestyle="--", linewidth=0.5)
    plt.grid(which="major", axis="y", color="gray", alpha=0.8, linestyle="--", linewidth=0.5)
    plt.legend()
    plt.savefig(savedir + "\\" + filename + "_pdf.png")
    plt.show()


fitlognormlhist.py

"""
ヒストグラムをフィッティング
累積分布関数を生成してフィッティング
"""

import os
import sys

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy.optimize import curve_fit
from scipy.special import erf
from scipy.stats import norm


# 対数正規分布
def lognormal(x, a, sigma, mu, c):
    return a * (1 / (np.sqrt(2 * np.pi * sigma**2) * x) * np.exp(-((np.log(x) - mu) ** 2) / (2 * sigma**2))) + c


# 対数正規分布 累積分布関数
def lognormal_erf(x, sigma, mu):
    return (1 / 2) * (1 + erf((np.log(x) - mu) / (np.sqrt(2 * sigma**2))))


if __name__ == "__main__":
    # === 対数正規分布作成 ===
    np.random.seed(1)  # 乱数を再現できるように
    mu = 3
    sigma = 1
    data_num = 1000
    lognorm_dat = np.random.lognormal(mu, sigma, data_num)

    # dataframeに格納
    label = "lognormal"
    df = pd.DataFrame(lognorm_dat, columns=[label])

    # ヒストグラム作成
    # ヒストグラムをplt.histで作成するのでここでfigureオブジェクト生成
    plt.figure(1)
    plt.style.use("ggplot")
    freq, bins, _ = plt.hist(
        [df[label]],
        bins=100,
        alpha=0.5,  # グラフの透過率 0が透明、1が不透明 未指定の場合は1
        # 		color=['#f46d43'] #グラフの色 未指定の場合は自動
        ec="navy",
        label=[label],  # グラフのラベル
        # range=(x_range_min, x_range_max),  # グラフの横軸の範囲 未指定の場合はデータの最大、最小値に合わせられる
        rwidth=1.0  # グラフの棒の幅 身指定の場合は1
        # 		stacked=False #複数データを積み上げグラフにするか、横に並べるか 未指定の場合はFalse
    )

    # 分布のx,yの値を設定
    # plt.histは端の値が返ってくるのでbins+1のデータ数がある
    # フィッティングはビンの中心の値を使うのでビンの差分を2で割って足す
    pdf_x = bins[0:-1] + np.diff(bins) / 2
    pdf_y = freq

    # 対数正規分布フィッティング
    # paramはフィッティングパラメータ、covは共分散行列
    param_ini = (10000, sigma, mu, 0)  # 初期値
    param, cov = curve_fit(lognormal, pdf_x, pdf_y, p0=param_ini)
    # 共分散のルートでフィッティングパラメータの不確かさ
    err = np.sqrt(np.diag(cov))
    # fitting関数からデータ作成
    pdf_y_fit = lognormal(pdf_x, param[0], param[1], param[2], param[3])

    # fitting係数出力
    print("・対数正規分布")
    print("a     : {:.6f} +- {:.6f}".format(param[0], err[0]))
    print("sigma : {:.6f} +- {:.6f}".format(param[1], err[1]))
    print("mu    : {:.6f} +- {:.6f}".format(param[2], err[2]))
    print("c     : {:.6f} +- {:.6f}".format(param[3], err[3]))
    print("\n")

    # フィッティングデータ保存
    # パラメータ
    name_pdf = np.array(["a", "sigma", "mu", "c", "a_sigma", "sigma_sigma", "mu_sigma", "c_sigma"])
    data_pdf = np.array([param[0], param[1], param[2], param[3], err[0], err[1], err[2], err[3]])
    data_pdf_df = pd.DataFrame([np.round(data_pdf, 6)])
    data_pdf_df.to_csv("pdf_fitting_param.csv", header=name_pdf, index=False)
    # フィッティングy
    name_pdf = np.array(["pdf_x", "pdf_y", "pdf_y_fit"])
    data_pdf = np.vstack((pdf_x, pdf_y, pdf_y_fit)).T
    data_pdf_df = pd.DataFrame(np.round(data_pdf, 6))
    data_pdf_df.to_csv("pdf_fitting.csv", header=name_pdf, index=False)

    # === 累積分布フィッティング ===
    cdf_x = sorted(df[label])
    cdf_y = [i / data_num for i in range(data_num)]

    param, cov = curve_fit(lognormal_erf, cdf_x, cdf_y)
    err = np.sqrt(np.diag(cov))
    print("・対数正規分布 累積分布関数")
    print("sigma : {:.6f} +- {:.6f}".format(param[0], err[0]))
    print("mu    : {:.6f} +- {:.6f}".format(param[1], err[1]))
    print("\n")
    cdf_y_fit = lognormal_erf(cdf_x, param[0], param[1])

    # フィッティングデータ保存
    # パラメータ
    name_cdf = np.array(["sigma", "mu", "sigma_sigma", "mu_sigma"])
    data_cdf = np.array([param[0], param[1], err[0], err[1]])
    data_cdf_df = pd.DataFrame([np.round(data_cdf, 6)])
    data_cdf_df.to_csv("cdf_fitting_param.csv", header=name_cdf, index=False)
    # フィッティングy
    name_cdf = np.array(["cdf_x", "cdf_y", "cdf_y_fit"])
    data_cdf = np.vstack((cdf_x, cdf_y, cdf_y_fit)).T
    data_cdf_df = pd.DataFrame(np.round(data_cdf, 6))
    data_cdf_df.to_csv("cdf_fitting.csv", header=name_cdf, index=False)

    # === グラフ描画 ===
    plt.plot(pdf_x, pdf_y_fit, label="fit")
    plt.title("log-normal")
    plt.xlabel("x")
    plt.ylabel("Frequency")
    plt.legend()  # 凡例表示
    plt.savefig("lognormal_hist.png")

    plt.figure(2)
    plt.plot(cdf_x, cdf_y, "o", label="data")
    plt.plot(cdf_x, cdf_y_fit, label="fit")
    plt.title("log-normal CDF")
    plt.xlabel("x")
    plt.ylabel("CDF")
    plt.legend()
    plt.savefig("lognormal_hist_cdf.png")
    plt.show()