satopoooonのブログ

自分向けの備忘録

pythonで波形処理プログラム-ガウスフィット-

ガウスフィット

pythonガウスフィットさせてその面積を求めるプログラムを作りたいです。
GUIで作りたい。

ひとまず、必要な機能は、
・matplotlibのグラフ上から、ポインタ情報を引っこ抜く
ガウスフィットさせる
あたりです。

以下のサイトを参考にしました。
python/matplotlibの図上にてクリックで座標値を取得したりキーボード入力値を取得したりする - Qiita
scipy optimizeをつかってみる (Python メモ) | OpenBook

やったことは、
1.ノイズ付きの正規分布をプロット、
2.グラフ上の2点を選択、
3.その間のデータを使ってガウスフィット、
4.フィッティング関数から面積を求める、

1.ノイズ付きの正規分布をプロット

import numpy as np
from scipy.stats import norm
# ベクトルxを [-5.0, ..., 5.0] の区間で作成
x = np.linspace(-1.0, 1.0, 100)

# 平均0, 標準偏差1の正規分布における、xの確率を求める
y = []
for i in range(len(x)):
    y.append(norm.pdf(x=x[i], loc=0, scale=1))

from scipy.optimize import curve_fit
#ノイズを作成
from numpy.random import *
y3 = normal(0.1,0.01,size = 100)

y = y + y3

f:id:satopoooon:20180129231340p:plain
こんな感じのグラフができます。
次は
2.グラフ上の2点を選択、、、
mpl_connectメソッドを使います。
第1引数が"クリック"によってイベント発生ということを指定して、
第2引数がクリックで実施することです。

#グラフ化
fig=plt.figure()
ax=fig.add_subplot(111)
ax.plot(x,y)
#グラフ上でクリックすることで、座標情報をひっぱります。
cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()

onclick関数は以下です。

def onclick(event):
    mask = np.ones(len(x), dtype=bool)
    global stat
    global leftind, rightind
    #stat = 1
    ind = np.searchsorted(x, event.xdata)
    plt.title("You clicked index=" + str(ind))
    print(stat,event.button)
    if event.button == 3 and stat == 1:
        leftind = ind
        ax.plot([x[ind]], [y[ind]], ".", color="red")
        stat = 2
    elif event.button == 3 and stat == 2:
        rightind = ind
        ax.plot(x[leftind:rightind], y[leftind:rightind], color="red")
        stat = 3

        gauss_return = gauss_fit(x[leftind:rightind],y[leftind:rightind])
        ax.plot(gauss_return[0],gauss_return[1], color="red")
        print(integ(x[leftind],x[rightind]))
    elif event.button == 1 and event.dblclick == 1 and stat == 3:
        plt.title("Approved")
        mask[leftind:rightind] = False
        stat = 1

    elif event.button == 2 and stat == 3:
        plt.title("Canceled")
        ax.plot(x[leftind:rightind], y[leftind:rightind], color="blue")
        ax.plot([x[leftind]], [y[leftind]], ".", color="green")
        stat = 1
    fig.canvas.draw()

ガウスフィットしたり、積分したりする関数は以下です。

def gauss_fit(x,y):
    global popt,pcov
    popt, pcov = curve_fit(gaussian,x,y)
    x_range = np.linspace(x[0], x[-1], 100)

    y_gauss = gaussian(x_range, np.ones(100) * popt[0], np.ones(100) * popt[1],
                  np.ones(100) * popt[2], np.ones(100) * popt[3])

    return x_range,y_gauss

def gaussian(x, a, mu, c, gamma):
    return a * np.exp(- gamma * (x - mu) ** 2) + c

def func(x):
    return popt[0] * np.exp(-popt[3] * (x - popt[1]) ** 2) + popt[2]

def integ(left,right):
    return integrate.quad(func,left,right)

ちなみにこんな感じでフィッティングされます。
f:id:satopoooon:20180129232617p:plain

jsonファイルと辞書型

JSONファイル

JSONファイルって何?
調べればすぐに出てきますけど(以下等参考)、
プログラムと人の両方が理解できる形式ってイメージです。
【Python入門】JSON形式データの扱い方 - Qiita
同じようなものにXMLとかあるけど、それよりも見やすい気がします。

visual studio codeで独自のスニペッツを作成しましたが、
そのルールを記載するファイルがjson形式でした。

データベースのテーブルとカラムが記載している表から、
json形式でスニペットを作成するスクリプトです。
辞書型を使うとすごい簡単にできました。

PATH = "データベースのテーブル、カラムが記載しているエクセルファイルのパス.xlsx"
dframe = pd.read_excel(PATH,sheetname="Sheet2")

list2 = {}
text = "" 
dict={}
for column in dframe.columns:
    list2[column] = dframe[column].dropna()
    for n in list2[column]:
        text =  n + "," + text 
    dict[column] = text

import json
file =open("ファイルのパス.json","w")
json_dict2 = {}

for key in dict.keys():
    json_dict= {}
    json_dict["prefix"]=key
    json_dict["body"]= key + ".${1|" +dict[key] + "none|}"
    json_dict2[key] = json_dict 

json.dump(json_dict2,file)

pythonで動的に変数を作成したい(for文でloopまわして作成)

動的に変数を作成

pythonでつまずいたことがあったのでメモ

for文でloopさせて、動的に変数作成をしたかったんですよ。
その際に、引数もfor文で作成的なやつです。

間違った例↓

for n in dataframe.colums
 "data_{}".format(n) = dateframe[n]

これはダメでしたね。
.formatは文字列に変数を代入するという方式みたいですね。

やるとしたら、
[[dateframe[1],[dateframe[2],・・・・,datafarame[n]]
みたいに、リスト内リストか辞書型が良いみたいです。

list = [] #リスト
for column in dframe.columns:
     list.append(dframe[column].dropna())

list2 = {} #辞書型
for column in dframe.columns:
    list2[column] = dframe[column].dropna()

リスト内リストだと引数が数字になるけど、
辞書型だと、引数に文字列が使えるので便利かな、

ちなみに下記を参考にすると、exec関数で解決できるっぽいですが、
変数となるタイミングの問題で推奨されていなよう。
Python - pythonでname0,name1,name2・・・のように変数を宣言したい|teratail
モジュール外から呼び出すと、想定外の動きしないとか、そういうバグ
具体例としては以下2つの違い

for i in range(3):
    code = 'name{} = {}'.format(i, 3 ** i)  # 例として3のi乗を代入
    exec(code)

print name0, name1, name2  # ==> 1 3 9
name1 = 123

def foo(num):
    exec('name{} = 456'.format(num))
    print name1  # 123

foo(1)

visual studio code のインテリセンスを自分好みに

はじめに

自分好みの補完機能が欲しくてVSCodeのインテリセンス機能を編集しました。
下記サイトを参考にしました。

vscode-doc-jp.github.io

実際にやったことは、
VSCodeSQLエディタとして使う際、
テーブル名とカラム名の保管機能を追加しました。

VScodeを開いて、
ファイル(Code) > 基本設定 > ユーザースニペット
SQLを選択します。
このファイルを編集することにより、任意の補完機能を追加することができます。
ファイル形式はjsonです。

"テーブル名": {
    "prefix": "テーブル名",
    "body": [
		"テーブル名.${1|カラム1,カラム2,カラム3|},"
	],
	"description": "説明"
},

prefixに補完する文字、
bodyに補完する内容、
ここでは、テーブル名が打ち込まれると、
テーブル名+カラム1〜3のどれかを選択できるようにしています。

テーブル名がそれほど多くなければテーブル名ごとに上記を書いていけば良いかと思います。
VSCodeでデータベースに接続すれば、もっと色々とできることは増えるかと思うんですが、、、
諸事情によりそれはできませんので、しばらくこの方法を使っていこうかと思います。

仮想通貨のお勉強その2 APIから情報を引っ張ってくる

APIからティッカー情報を引っ張ってくる

下記サイトを参考にして(というかそのまま)、さわりだけ勉強、
https://qiita.com/ti-ginkgo/items/7e15bdac6618c07534be

requestsってライブラリは初めて使いました。
何するライブラリなの?
下記サイトを参考にさせてもらいました。
Requests の使い方 (Python Library) - Qiita
httpライブラリらしいですね。使いやすそう。

ティッカー情報をgetします。

import requests
import json
from pandas import DataFrame

URL = 'https://coincheck.com/api/ticker'
coincheck = requests.get(URL).json()

#json形式のデータから、keyとlistを引っ張ってくる、
#さらにデータ形式を揃えて見やすい形に直します。
for key, item in coincheck.items():
    print("%-9s : %-10.9s " % (key, item))

以下別の方法、
http://soy-curd.hatenablog.com/entry/2017/05/06/013515

from coincheck import market

m = market.Market()
result = m.ticker()
print(result)

昔のデータも引っ張ってこれます。

import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib


df = pd.read_csv("http://api.bitcoincharts.com/v1/trades.csv?symbol=coincheckJPY",
                 header=None,
                 parse_dates=True,
                 date_parser=lambda x: datetime.fromtimestamp(float(x)),
                 index_col='datetime',
                 names=['datetime', 'price', 'amount'])

df["price"].plot()
plt.show()

f:id:satopoooon:20180107223450p:plain

ひっぱてきた情報をデータベースに保存できれば、良さげ、
データベースの勉強もしないと

仮想通貨のお勉強

仮想通貨

世の中流行ってますね。
冬休みでまとまった時間があったので勉強してみました。
色んなブログやら書籍やらありますが、主に下記を読みました。
結構ボリュームがあるので、大枠しか読んでませんが、、、
わからないことは、いろいろググりながら読み進めました。
https://www.bitcoinbook.info/translations/ja/book.pdf

ブロックチェーンやらマイニングってなんですかね、

ブロックチェーンって何?
複数の取引(トランザクション)がまとまって1個のブロックになっており、
複数のブロックが鎖上に繋がっている。
ブロックの中身は下記図の通り、
https://tech-camp.in/note/wp-content/uploads/fig_blockchain.png
トランザクション以外にも、前ブロックのハッシュ値やnonceで構成されている。

Bitcoin等の仮想通貨は、ウォレットというものは、このブロックごとの取引情報をかき集めて、合計金額とします。
実際に一つのストレージに個人のお金情報を集めているわけではにです。
なので、個人のお金はブロック毎に分散されて保存されています。

・マイニングって何すること?
ブロックチェーンにおける合意形成(売買の承認)の方法で、
マイナーと呼ばれる人たちが実施しています。
マイナーはマイニングの対価として、仮想通貨を得ます。

流れとしては、
P2Pネットワークを伝わってくるトランザクション情報を、
マイナーはローカルのデータプールにいくつか集め、それらを加工することにより新規ブロックにして、
最後にチェーンにつなげます。
チェーンに繋いだら、繋いだ事を別のマイナー達に伝えます。
別のマイナーは、これを承認します。

尚、トランザクションには優先順位(マイナーに支払われる手数料、取引時間等で決まる)があるので、
優先順位が低いものは次のブロックへ廻されます。

具体的にマイングとは、何をするかというと、
トランザクション+nonce+前ブロックのハッシュ値」のハッシュ値が、
ある特定の値以下になるように、nonceを決めることです。
このnonceを決める(総当たり的に計算する)のがマイニングです。
「ある特定の値以下」の値は流動的で、
マイニングが10分程度になるように、調整されます。
マイニングは、コンピューターの性能に依存するので、
高性能のコンピュータならすぐ計算できるし、そうでなければ遅くなります。

kaggleに挑戦その5 過学習、学習不足の可視化

学習曲線

データセットに対してモデルが複雑すぎる場合、過学習する傾向があり汎化性能が落ちてしまう。
レーニングデータをさらに集めると、過学習は抑えることができるが、データをさらに集めることはコストが非常に高い。
また、実はこれ以上データを集めても無駄ということもある。 そんなとき、学習曲線を使うことでデータを集めることに価値があるか、検証できる。

f:id:satopoooon:20171226232023j:plain
有名な過学習、学習不足の絵ですね。

過学習と、学習不足が丁度良いバランスの場合、
レーニングデータセットから作成したモデルの精度と、
そのデータを(例えば)K分割交差検証で評価したモデルの精度が同程度になります。

逆にすでに同程度の場合、これ以上サンプル数を増やしても精度は上がらないですね。
精度を上げたい場合は、モデル自体を変えた方が良いことになります。

今回作成したモデルはどうなんでしょう、、、

import matplotlib.pyplot as plt
from sklearn.learning_curve import learning_curve

train_sizes,train_scores,valid_scores = learning_curve(estimator=forest,
                            X=X_train,
                            y=y_train,
                            train_sizes=np.linspace(0.1,1.0,10),
                            cv=10,
                            n_jobs=1)

train_mean = np.mean(train_scores,axis = 1)
test_mean = np.mean(valid_scores,axis=1)

plt.plot(train_sizes,train_mean)
plt.plot(train_sizes,test_mean)
plt.show()

f:id:satopoooon:20171226233839p:plain
過学習してますねー。
データ数増やしていけば、過学習を抑えることができるってことがわかります。
実際は、データ数を増やすことはできないので、
モデルの複雑さを抑えて汎化性能を上げる必要があるかと思います。