ロジスティック回帰

[ロジスティック回帰]は、類似度を確立によって表現する
→ ”ユークリッド距離”、”コサイン類似度”に比べて、より踏み込んだ情報を得ることが可能
→ 確率pで1、確率1-pで0を取るような離散確率分布ベルヌーイ分布を元に、確率的に1か0の値を取るものと考える

公式
ある入力xを、出力y={1,0}のいずれかに分類することを考え、y=1となる条件付き確率p(y=1|x;θ)を以下のように定義する
p(y=1|x;θ) = 1 / (1 + exp(-θ^Tx)

※p(θ)= 1/(1*exp(-θ)) はロジスティック関数

from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_validate

def main():
	dataset = datasets.load_breast_cancer()
	X, y = dataset.data, dataset.target

	clf = LogisticRegression()
	skf = StratifiedKFold(shuffle=True)
	scoring = {
		'acc' : 'accuracy',
		'auc': 'roc_auc',
	}
	scores = cross_validate(clf, X, y, cv=skf, scoring=scoring)

	print('Accuracy(mean):', scores['test_acc'].mean())
	print('AUC(mean):', scores['test_auc'].mean())

if __name__ == '__main__':
	main()

Accuracy(mean): 0.9490299823633156
AUC(mean): 0.992996071668104

TF-IDF(Term Frequency-Inverse Document Frequency)

TFはTerm Frequency(単語頻度)
IDFはInverse Document Frequency(逆文章頻度): 単語を含む文章がどれだけの頻度で出現していないか、珍しさを表す指標

TFはN個の単語の内、n回表示だと、n/N で表すので、そのまま。
IDFはD個の文で単語tを含む文がd個ある時、 IDF = -log[10]d/D = log[10]D/d となる。指標が、[文章]単位に変わる。

TF-IDFはTFとIDFの積
単語の頻度と文章の頻度を掛ける

では実践してみましょう。

from math import log
import pandas as pd 

docs = [
	["ノンプレイヤーキャラクター", "プレイヤー","操作","キャラクター"],
	["プレイヤー","操作","キャラクター","プレイヤーキャラクター"],
	["NPC","PC"],
	["RPG用語","コンピューターゲーム","キャラクター","人間らしく","操作"],
	["NPC","ゲームマスター","プレイヤー","キャラクター","ゲーム","イベント","バランス","プレイヤー"]
]

words = list(set(w for doc in docs for w in doc))
words.sort()
print(words)

# TF-IDF
N = len(docs)

def tf(t, d):
	return d.count(t)/len(d)

def idf(t):
	df = 0
	for doc in docs:
		df += t in doc

	return log(N/df)+1

def tfidf(t,d):
	return tf(t,d)* idf(t)

# TF
result = []
for i in range(N):
	result.append([])
	d = docs[i]
	for j in range(len(words)):
		t = words[j]

		result[-1].append(tf(t,d))

tf_ = pd.DataFrame(result, columns=words)
print(tf_)

# IDF
result = []
for j in range(len(words)):
	t = words[j]
	result.append(idf(t))

idf_ = pd.DataFrame(result, index=words, columns=["IDF"])
print(idf_)

# TF-IDF
result = []
for i in range(N):
	result.append([])
	d = docs[i]
	for j in range(len(words)):
		t = words[j]

		result[-1].append(tfidf(t,d))

tfidf_ = pd.DataFrame(result, columns=words)
print(tfidf_)

[vagrant@localhost python]$ python app.py
[‘NPC’, ‘PC’, ‘RPG用語’, ‘イベント’, ‘キャラクター’, ‘ゲーム’, ‘ゲームマスター’, ‘コンピューターゲーム’, ‘ノンプレイヤーキャラクター’, ‘バランス’, ‘プレイヤー’, ‘プレイヤーキャラクター’, ‘人間らしく’, ‘操作’]
NPC PC RPG用語 イベント キャラクター … バランス プレイヤー プレイヤーキャラクター 人間らしく 操作
0 0.000 0.0 0.0 0.000 0.250 … 0.000 0.25 0.00 0.0 0.25
1 0.000 0.0 0.0 0.000 0.250 … 0.000 0.25 0.25 0.0 0.25
2 0.500 0.5 0.0 0.000 0.000 … 0.000 0.00 0.00 0.0 0.00
3 0.000 0.0 0.2 0.000 0.200 … 0.000 0.00 0.00 0.2 0.20
4 0.125 0.0 0.0 0.125 0.125 … 0.125 0.25 0.00 0.0 0.00

[5 rows x 14 columns]
IDF
NPC 1.916291
PC 2.609438
RPG用語 2.609438
イベント 2.609438
キャラクター 1.223144
ゲーム 2.609438
ゲームマスター 2.609438
コンピューターゲーム 2.609438
ノンプレイヤーキャラクター 2.609438
バランス 2.609438
プレイヤー 1.510826
プレイヤーキャラクター 2.609438
人間らしく 2.609438
操作 1.510826
NPC PC RPG用語 イベント … プレイヤー プレイヤーキャラクター 人間らしく 操作
0 0.000000 0.000000 0.000000 0.00000 … 0.377706 0.000000 0.000000 0.377706
1 0.000000 0.000000 0.000000 0.00000 … 0.377706 0.652359 0.000000 0.377706
2 0.958145 1.304719 0.000000 0.00000 … 0.000000 0.000000 0.000000 0.000000
3 0.000000 0.000000 0.521888 0.00000 … 0.000000 0.000000 0.521888 0.302165
4 0.239536 0.000000 0.000000 0.32618 … 0.377706 0.000000 0.000000 0.000000

[5 rows x 14 columns]


TFは頻度なので、0≦TF≦1になってますね。
IDFは、”プレイヤー”や”キャラクター”など、使用頻度の高い方が、値が小さくなってます。log[10]D/dなので、dの値が大きくなるほど、IDFは小さくなることがわかります。
そしてTF-IDFは、TF同様、文章ごとに値が表示されます。

あ、IDFは珍しいワードの方が値が大きくなるので、TF-IDFで各単語の重み付けをして特徴を示しているんですね。

このロジック考えたの誰だよ、すごいな。。。

Bag-of-Words

単語にベクトルの各列を割り当てておいて、出現回数などを要素とすることで文章をベクトル化したものを、Bag-of-Wordsベクトルと呼ぶ。

scikit-learnのCountVetctorizer
トランプ大統領の発言を解析します。

import numpy as np 
from sklearn.feature_extraction.text import CountVectorizer
count = CountVectorizer()
docs = np.array([
		'If you want freedom, take pride in your country. If you want democracy, hold on to your sovereignty. If you want peace, love your Nation',
		'President Donald J. Trump has shown that the path to prosperity and strength lies in lifting up our people and respecting our sovereignty'
	])
bag = count.fit_transform(docs)
print(count.vocabulary_)

[vagrant@localhost python]$ python app.py
{‘if’: 7, ‘you’: 32, ‘want’: 31, ‘freedom’: 4, ‘take’: 25, ‘pride’: 19, ‘in’: 8, ‘your’: 33, ‘country’: 1, ‘democracy’: 2, ‘hold’: 6, ‘on’: 13, ‘to’: 28, ‘sovereignty’: 23, ‘peace’: 16, ‘love’: 11, ‘nation’: 12, ‘president’: 18, ‘donald’: 3, ‘trump’: 29, ‘has’: 5, ‘shown’: 22, ‘that’: 26, ‘the’: 27, ‘path’: 15, ‘prosperity’: 20, ‘and’: 0, ‘strength’: 24, ‘lies’: 9, ‘lifting’: 10, ‘up’: 30, ‘our’: 14, ‘people’: 17, ‘respecting’: 21}

アメリカの大統領ともなると、”you”って言葉を多用されるのでしょうか。
単語ベクトルと言うと、mecabの頻出単語とは異なる印象です。

MSEとR^2

MSEとR^2 って、六本木のバーのような名前ですが、
Mean Squared Error: MSE
→残差の2乗平均を取ったもの
1/n*nΣi=1(y実測値i – y予想値i)^2
あれ、MSEって、テストデータと検証データのnが一緒でないといけない??

決定係数: R^2
R^2 = 1 – MSE – / 1/n*nΣi=1(y実測値i – y予想値i)^2 (0≦R^2≦1)

MSE

from sklearn.metrics import mean_squared_error
y_true = [4, -0.2, 3, 6]
y_pred = [3.5, 0.0, 2, 8]

print(mean_squared_error(y_true, y_pred))

[vagrant@localhost python]$ python app.py
1.3225

R^2

from sklearn.metrics import r2_score
y_true = [4, -0.2, 3, 6]
y_pred = [3.5, 0.0, 2, 8]

print(r2_score(y_true, y_pred))

[vagrant@localhost python]$ python app.py
0.7365537848605578

交差検証法

統計学において標本データを分割し、その一部を解析して、残る部分で解析のテストを行い、解析の妥当性の検証・確認に当てる
→ これ以上標本を集めるのが困難な場合に有効

主な種類
– ホールドアウト検証
初期標本群から事例を無作為に抽出
– K-分割交差検証
標本群をK個に分割し、その一つをテスト事例、残りを訓練事例
– Leave-one-out cross validation
標本群から一つだけ抜き出し、残りを訓練。これを全事例が一回ずつテスト事例になるよう繰り返す

色々手法があるが、やはり信ぴょう性にはデータ量が物を言うような印象

正則化(Reguralization)

正則化とは、モデルが複雑になると、ペナルティが課されるような項を追加することで過学習を防ぐ
一般的には、L1正則化、L2正則化を用いる
正則化項 λE(w) = λLΣK=1|Wk|
重みWのノムルが大きくなりすぎない(複雑になりすぎない)ようにL2ノムルを追加し、Dを最小化する。
ここでλは、定数値として定め、λが大きいと、ノムルの値が小さくなる。
λの値を調整することで、正則化の度合いを調整する。

えーと、確かL1ノムルは絶対値の値、L2ノムルはユークリッド距離でしたね。
あれ、ってことは、L1ノムル(絶対値の和)で正則化することもあれば、L2ノムル(ユークリッド距離)で正則化することもあるってことね。
関数Dの最小化だから、微分するってことなんだろうけど、例えば重回帰分析とかなら、正則化の項は付いてなかったように記憶しているが、、、

ここは理解が乏しいな。。

最小二乗法

まず、散布図を作成します。

import matplotlib.pyplot as plt 

x = [1,2,3,4,5]
y = [1571,1630,1681,1603,1623]

plt.scatter(x, y)

合計距離の最小値を求める
D = 5Σ[t=1]*{yl – (w0 + w1xl)}^2

実装する

import numpy as np
import matplotlib.pyplot as plt 

x = np.array([1,2,3,4,5])
y = np.array([1571,1630,1681,1603,1623])

def reg1dim(x, y):
	a = np.dot(x, y)/ (x ** 2).sum()
	return a 

a = reg1dim(x, y)

plt.scatter(x, y, color="k")
plt.plot([0,x.max()], [0,a * x.max()])

ああああああああああ、全然やりたいことと違う
plotする時に、0からスタートすると駄目なのか。。

平均(mean)は、np.mean()だから、こうか?

x = np.array([1,2,3,4,5])
y = np.array([1571,1630,1681,1603,1623])

m = np.mean(y)

def reg1dim(x, y):
	a = np.dot(x, y)/ (x ** 2).sum()
	return a 

a = reg1dim(x, y)

plt.scatter(x, y, color="k")
plt.plot([0,x.max()], [m,a * x.max()])

あれ、なんかちゃうなー、 [m,a * x.max()]のところがおかしい。。

最小二乗法はこういう図になるはずなんだけど。。

最尤推定

最尤推定法: ある自由パラメーターが与えられた時に、モデルが実データを予測する確率を最大化するような自由パラメーターを求める方法
→ 観測結果が偶然偏ってしまった場合や、適用する確率分布仮定を誤ると、見当違いな推定結果が導かれる

よって、回数を増やさないと、信用度が上がらない
性善説に立っているようですね。

最尤推定とは、パラーメータθに関する尤度関数L(θ)を最大化するθを求める
θを求めるには、一階級微分するが、対数尤度関数log[e]L(θ)を取る

公式
d/dθ*log[e]L(θ) = 0

最尤推定は、過去データから将来を予想する時に用いられることが多い
まぁ、データ量が上がれば精度も上がるということでしょう。

相関係数

nikkeiとdowの相関を見て見ましょう。

nikkei
2019/10/4 21,316 21,410 21,276 21,410
2019/10/3 21,422 21,437 21,277 21,341
2019/10/2 21,744 21,795 21,725 21,778
2019/10/1 21,831 21,938 21,811 21,885
2019/9/30 21,793 21,811 21,666 21,755

dow
2019年10月04日 26,573.72 26,271.70 26,590.74 26,271.70 224.49M 1.42%
2019年10月03日 26,201.04 26,039.02 26,205.20 25,743.46 249.02M 0.47%
2019年10月02日 26,078.62 26,425.86 26,438.04 25,974.12 312.73M -1.86%
2019年10月01日 26,573.04 26,962.54 27,046.21 26,562.22 272.18M -1.28%
2019年09月30日 26,916.83 26,852.33 26,998.86 26,852.33 228.48M 0.36%

import numpy as np
import pandas as pd

nikkei = [21410,21341,21778,21885,21755]
dow = [26573.72,26201.04,26078.62,26573.04,26916.83]
s1 = pd.Series(nikkei)
s2 = pd.Series(dow)
print(s1.corr(s2))

[vagrant@localhost python]$ python app.py
0.24461988452298797

あれ、思ったより全然相関してない??
dowに反応して日経が動く傾向とすれば、nikkeiを1日ずらせばいいのかな。

平均、分散、標準偏差

普通にやっても詰まらないので、日経平均の平均を取りましょう

日付、始値、高値、安値、終値

2019/10/4	21,316	21,410	21,276	21,410
2019/10/3	21,422	21,437	21,277	21,341
2019/10/2	21,744	21,795	21,725	21,778
2019/10/1	21,831	21,938	21,811	21,885
2019/9/30	21,793	21,811	21,666	21,755
nikkei = [21410,21341,21778,21885,21755]
print(sum(nikkei)/len(nikkei))

[vagrant@localhost python]$ python app.py
21633.8

分散は

import numpy as np

nikkei = [21410,21341,21778,21885,21755]
print(np.var(nikkei))

[vagrant@localhost python]$ python app.py
46880.56

標準偏差は、print(np.std(nikkei))とします。

[vagrant@localhost python]$ python app.py
216.5191908353622

あああ、今週は動きましたねーーーー