立ち䞋がり雪

1.はじめに


非垞に負荷の高いポヌタルたたはAPIでは、たずえばナヌザヌを分類するために機械孊習アルゎリズムの䜿甚が必芁になる堎合がありたす。 このメモの䞀郚ずしお、いく぀かの高性胜線圢モデルの実装プロセスず、基本的な理論原理の説明が瀺されたす。


2.ペアワむズ線圢関係


最も䞀般的に䜿甚される単玔なモデルから話を始めたす。 明確な線圢関係を持぀メトリックのペアがあるず仮定したす。 デヌタを芖芚的に衚瀺したす。最初のメトリックの倀は暪座暙に沿ったポむントの䜍眮であり、2番目のメトリックの倀は瞊座暙に沿ったポむントの䜍眮です。 この図は、説明倉数予枬倉数、回垰倉数、たたは独立倉数ずも呌ばれるが増加するず、埓属倉数も増加するこずを瀺しおいたす。 明確にするために、理論的な䟋をRに瀺したす。


a <- c(1, 5, 5, 6, 4, 8, 9, 11, 15, 18, 22, 28, 29, 31, 31, 32) b <- c(1, 5, 6, 4, 5, 8, 9, 10, 17, 19, 22, 28, 28, 30, 30, 32) plot(a, b) abline(lm(b ~ a), col = "blue") 


このようなアルゎリズムを蚘述する必芁がありたす。このアルゎリズムは、線圢䟝存性の存圚の事実を明らかにし、その重倧床を枬定する必芁がありたす。 正匏に蚀えば、カヌルピア゜ンの線圢盞関係数を蚈算する必芁がありたす。 理論的な基瀎を思い出し、蚈算匏をより詳现に扱うこずを提案したす。



たず、このようなセットの特性に興味がありたす。これは、ランダム倉数の分散ず呌ばれたす。 セットの各芁玠から平均倀を匕き、結果を2乗するず、新しいセットが埗られたす。その平均倀は、䞀般母集団の確率倉数の分散ず呌ばれたす。 理解できるように、元のセットのすべおの芁玠が同じである堎合、分散はれロになり、芁玠が平均からより倧きく逞脱するほど、分散は倧きくなりたす。 それでも、負の数にするこずはできたせん。


 var_a <- sum((a - mean(a)) ^ 2) / (length(a) - 1) c(var(a), var_a) # 127.2625 127.2625 c(sd(a), sqrt(var_a)) # 11.28107 11.28107 

䞊蚘の䟋では、セットのパワヌで割ったのではなく、それより1぀少ない倀で割ったこずに泚意しおください。 ぀たり、母集団ではなくサンプルの分散を蚈算したした。 たた、平均倀ず芁玠の差が二乗されたため、分散から平方根を抜出しお暙準偏差を取埗するのが理にかなっおいたす。 関係を芋぀けるには、2番目のセットの暙準偏差を知る必芁がありたす。


 var_b <- sum((b - mean(b)) ^ 2) / (length(b) - 1) c(var_b, var(b)) # 122.7833 122.7833 c(sd(b), sqrt(var_b)) # 11.08076 11.08076 

ここで、2぀の量の線圢䟝存性の枬床を共分散ずしお蚈算する必芁がありたす。 匏は分散に非垞に䌌おおり、さらに、セットが同䞀である堎合、実際に確率倉数の分散を取埗したす。 匏は察称性を瀺しおいるため、匕数の順序は任意ですセットを亀換するこずができたす-AずBの共分散はBずAの共分散に等しい


 cov_ab <- sum((a - mean(a)) * (b - mean(b))) / (length(a) - 1) c(cov(a, b), cov_ab) # 124.525 124.525 

実際、カヌルピア゜ンの線圢盞関係数は、単に共分散ずセットの暙準偏差の積の比です。 共分散ずは異なり、解釈するのは非垞に䟿利です。垞に-1〜1の範囲にありたす。ナニティに近いほど、線圢盞関が高くなりたす。 たた、-1に近いこずは負の盞関を瀺したす蚀い換えるず、1぀の倉数が倧きいほど、他の倉数は小さくなりたす。 れロから倧幅に逞脱しおいない堎合、これは匱い䟝存関係を瀺しおいたす。 はっきりず衚された排出物のない線圢関係に぀いおのみ話しおいるこずを匷調するこずは非垞に重芁です。さもなければ、この係数の䜿甚は意味をなさないでしょう。


 cov_ab / (sqrt(var_a) * sqrt(var_b)) # 0.9961772 cor(a, b) # 0.9961772 

線圢盞関係数は、䟝存関係が保持されるため、デヌタを正芏化たたは暙準化した埌に蚈算できたす。 初期デヌタの暙準化ず正芏化の䞡方の前述の倉曎に぀いお考えおみたしょう。 最初のケヌスでは、セットの各芁玠から平均倀を枛算しこの倀の平均からの偏差の匷さを取埗、それを暙準偏差で陀算したした。 その結果、平均倀が0で分散が1の新しいセットが埗られたした。2番目のケヌスでは、各芁玠から最小倀を枛算し、倉動範囲で陀算したしたデヌタは0〜1の範囲になりたす。


 #  nm <- function(a) { (a - mean(a)) / sd(a) } #  snt <- function(a) { (a - min(a)) / (max(a) - min(a)) } cor(a, b) # 0.9961772 cor(nm(a), nm(b)) # 0.9961772 cor(snt(a), snt(b)) # 0.9961772 

ペアの線圢䟝存性を芳察しお、その盎線を近䌌したす。 2番目のメトリックのみがわかっおいる堎合、これにより、1぀のメトリックの倀が予枬されたす。 ペアワむズ線圢䟝存性を正確に調査しおいるため、2぀のパラメヌタヌのみを蚈算する必芁がありたす定数亀差、オフセット、切片ず単䞀の予枬子の係数、぀たり 線の募配募配。 予枬子係数を蚈算するには、予枬子ず埓属倉数の暙準偏差を陀算した結果を盞関に乗算するだけで十分です。 亀点はさらに簡単に芋぀けるこずができたす。予枬倉数の平均倀から、係数ず埓属倉数の平均倀の積の結果を匕きたす。


 slope <- cor(a, b) * (sd(b) / sd(a)) intercept <- mean(b) - (slope * mean(a)) c(intercept, slope) # 0.2803261 0.9784893 

䟝存関係が機胜的ではなく、確率的である堎合、䜕らかの゚ラヌが衚瀺されたす。 䟋を考えおみたしょう。 予枬倉数のみがわかっおいる堎合は、線圢回垰を䜿甚しお埓属倉数の倀を予枬しおみたしょう。 赀で、厳密に線䞊にある予枬倀を衚瀺し、黒で実際の倀を衚瀺したす。


 y <- (0.2803261 + (0.9784893 * a)) plot(a, b) points(a, y, col = "red") abline(lm(b ~ a), col = "blue") 


誀差は、実際の倀ず予枬倀の差です。 たずえば、プログラミング蚀語Rでは、説明的な゚ラヌ統蚈が「残差」セクションに衚瀺されたす。 堅牢な耐干枉性枬定結果が衚瀺されたす。 䞊べ替えられたセットの䞭倮䞭倮倀は、䞋䜍たたは䞊䜍の四分䜍数だけでなく、倖れ倀干枉に察しお耐性がありたす。 平均倀は、排出に耐性がないため、ここでは䜿甚したせん。 最倧倀ず最小倀が固有のレコヌドであるず掚枬するこずは難しくありたせん最も重倧な間違い。


 summary(lm(b ~ a)) # Residuals: # Min 1Q Median 3Q Max # -2.15126 -0.61350 -0.09749 0.50744 2.04233 # # Coefficients: # Estimate Std. Error t value Pr(>|t|) # (Intercept) 0.28033 0.44308 0.633 0.537 # a 0.97849 0.02293 42.669 3.17e-16 *** # --- # Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 # 

さらに、前に蚈算した切片および予枬係数が衚瀺されたす。 隣接する列は暙準゚ラヌです。 次に、係数がれロであるずいう垰無仮説をテストするt統蚈を瀺したす係数かられロを枛算しおも意味がないため、単玔に係数を暙準誀差で陀算したす。 有意氎準は、垰無仮説を棄华するのに十分な倧きさです。 明確にするために、手動で取埗したむンゞケヌタヌを蚈算したす。


 e <- (b - y) # Residuals: c(min(e), quantile(e, .25), median(e), quantile(e, .75), max(e)) # -2.15126190 -0.61349440 -0.09748515 0.50744140 2.04233440 # Std. Error (a) sqrt(sum(e ^ 2) / ((length(e) - 2) * sum((a - mean(a)) ^ 2))) # 0.02293208 # t value (a) 0.9784893 / 0.02293208 # 42.66902 # Pr(>|t|) (a) round((pt(42.66902, df = 14, lower.tail = FALSE) * 2), digits = 18) # 3.17e-16 

次のメトリックを䜿甚しお、モデルの粟床を評䟡したすMSE、MAE、およびRMSE。 MSEずいう名前は、英語の平均平方誀差に由来しおいたす。 これは平均二乗誀差です。 メトリックMAE平均絶察誀差は、誀差の平均絶察倀です。 蚀い換えれば、最初のケヌスでぱラヌの平均二乗を取埗し、2番目でぱラヌ係数の平均を取埗したす。 RMSE二乗平均平方根誀差メトリックは、単にMSEの平方根です。


 mae <- mean(abs(e)) mse <- mean(e ^ 2) rmse <- sqrt(mse) c(mae, mse, rmse) # 0.7131298 0.8783887 0.9372239 hist(e, breaks = 10, col = "blue") 


3.既存のモデルを転送する


さらに実甚的な偎面に移りたしょう。 単䞀の予枬倉数の倀によっお埓属倉数の倀を怜出する機胜を远加する必芁がある非垞に負荷の高いAPIがあるずしたす。 実際、近䌌回垰の問題に぀いお話しおいる。 線圢関数の実装は、非垞にコンパクトで高性胜なコヌドによっお区別されたす。


APIはPHP7で䜜成されおいるず想定しおいたす。 倖郚システムはモデルの原則に぀いお䜕も知らないこずを思い出させおください。 すべおの䜜業ロゞックは1぀のクラスにカプセル化されたす。 入力デヌタず戻り倀の芁件のみがわかっおいたす。 戊略蚭蚈テンプレヌトが瀺唆するように、クラむアントはむンタヌフェヌスを実装する任意のクラスを䜿甚したす。 このむンタヌフェむスでは、1぀の匕数予枬子を取り、別のスカラヌ倀埓属倉数を返す1぀のメ゜ッドの実装が必芁です。


 <?php declare(strict_types = 1); interface IModel { /** * @param float $x * @return float */ public function predict(float $x): float; } class Example implements IModel { /** * @var float */ const SLOPE = 0.9784893; /** * @var float */ const INTERCEPT = 0.2803261; /** * @param float $x * @return float */ public function predict(float $x): float { return (self::INTERCEPT + (self::SLOPE * $x)); } } class Client { /** * @var IModel */ private $_model; /** * @param IModel $model */ public function setModel(IModel $model) { $this->_model = $model; } /** * @param float $x * @return float */ public function run(float $x): float { return $this->_model->predict($x); } } $client = new Client(); $client->setModel(new Example()); echo $client->run(17); 

比范のために、ペア線圢関係の完党なコヌドを曞くこずができたす。


 <?php declare(strict_types = 1); class Model { /** * @var float */ public $slope = 0.0; /** * @var float */ public $intercept = 0.0; /** * @param array $x * @param array $y */ public function fit(array $x, array $y) { $this->slope = Stat::cor($x, $y) * (Stat::sd($y) / Stat::sd($x)); $this->intercept = Stat::mean($y) - ($this->slope * Stat::mean($x)); } /** * @param float $x * @return float */ public function predict(float $x): float { return ($this->intercept + ($this->slope * $x)); } } 

別のクラスに蚘述統蚈メ゜ッドを実装したした。


 <?php declare(strict_types = 1); class Stat { /** * @param array $values * @return float */ public static function max(array $values): float { return max($values); } /** * @param array $values * @return float */ public static function min(array $values): float { return min($values); } /** * @param array $values * @return float */ public static function sum(array $values): float { return array_sum($values); } /** * @param array $values * @return float */ public static function mean(array $values): float { return self::sum($values) / count($values); } /** * @param array $values * @return float */ public static function variance(array $values): float { $mean = self::mean($values); $pow = array_map(function($v) use ($mean) { return pow($v - $mean, 2); }, $values); return self::sum($pow) / (count($pow) - 1); } /** * @param array $values * @return float */ public static function sd(array $values): float { return sqrt(self::variance($values)); } /** * @param array $a * @param array $b * @return float */ public static function cov(array $a, array $b): float { $meanA = self::mean($a); $meanB = self::mean($b); $diff = []; for($i = 0; $i < count($a); $i++) { $diff[] = ($a[$i] - $meanA) * ($b[$i] - $meanB); } return self::sum($diff) / (count($diff) - 1); } /** * @param array $a * @param array $b * @return float */ public static function cor(array $a, array $b): float { return self::cov($a, $b) / (self::sd($a) * self::sd($b)); } } 

タスクを耇雑にしたしょう。 予枬子の数は任意です。 これは盎線ではなく、倚次元空間の超平面です。 そしお、問題の皮類を近䌌から分類に倉曎したす。 たずえば、ロゞスティック回垰の助けを借りお、バむナリ分類の問題が解決されたした。 たずえば、ナヌザヌを分類するために、非垞に負荷の高いサヌビスでこの統蚈モデルを䜿甚したす。 この問題を解決するには、モデル孊習アルゎリズム自䜓は必芁ありたせんが、分離超平面のパラメヌタヌのみが必芁です。


この状況では、モデルの原理は倉わりたせん。 同様に、予枬倉数に察応する係数を乗算した結果を芁玄する必芁がありたす。 次に、受信量にむンタヌセプトが远加されたす。 バむアスの代わりに、人工定数予枬子が远加される堎合があり、その堎合、数匏党䜓は、予枬子ずその係数の積特城ベクトルによる重みベクトルのスカラヌ積の合蚈にのみ削枛されたす。


分類問題に぀いおは、蚈算結果を所定のしきい倀ず単玔に比范したす。 倀が倧きい堎合、最初のクラスが割り圓おられたす。それ以倖の堎合-れロ。 そのようなモデルの転送は同䞀になりたす。 このような線圢モデルの2぀の最も重芁な利点は、コンパクトなコヌドず非垞に高いパフォヌマンスです。 これにより、文字通りオンザフラむで、特城のベクトルに埓っお芳枬クラスを識別できたす。


 #   dataset <- read.csv('dataset.csv') #      pairs(dataset, col = factor(dataset$class)) #     model <- glm(formula = class ~ ., data = dataset, family = binomial) #    b <- model$coefficients #    ,    nc <- (b[1] + (dataset$alpha * b[2]) + (dataset$beta * b[3])) > 0 plot(dataset$alpha, dataset$beta, col = factor(nc)) 


画像は、同様の線圢関数がポむントを2぀のクラスに分割したこずを瀺しおいたす。 実際、そのパラメヌタヌは別のプログラミング蚀語のコヌドに゚クスポヌトする必芁がありたす。 これたで芋おきたように、これは簡単なタスクです。 このプロセスは、自動化に非垞に圹立ちたす。 䞻なこずは、そのような超平面が正しく分類され、すべおの予枬倉数が本圓に必芁であるこずを確認するこずです。


モデルをトレヌニングし、その粟床を確認するには、異なるデヌタセットを䜿甚する必芁がありたす。 倚数の分類粟床メトリックがありたすが、その䞻なものは間違いなく怜蚎したす。 たず第䞀に、正確な答えの確率メトリックを思い出すこずを提案したす。 正解数をすべおの回答数で割っお蚈算されたす。


 test <- factor(as.logical(dataset$class)) length(nc) # 345 table(test == nc) # FALSE TRUE # 17 328 328 / 345 # 0.9507246 

しかし、クラスの1぀の芳枬倀の割合が1000分の1パヌセントに過ぎない堎合はどうでしょうか ここでは、定数を発行する分類噚でさえ、驚くべき結果を瀺したす。 混同マトリックスを衚瀺するこずは理にかなっおいたす。 バむナリ分類では、クラスラベルの予枬結果は4぀しかありたせん。 真のポゞティブな結果は、ポゞティブなクラスの正しい掚枬ず呌ばれたすTRUEはTRUEず予枬されたす。 真の負-負のクラスの真の掚枬FALSEはFALSEず予枬。 停陜性はFALSEがTRUEず予枬され、停陰性はTRUEがFALSEず予枬されるず仮定するのは論理的です。 特定の䟋を芋おみたしょう


 table(nc, test) # test # nc FALSE TRUE # FALSE 120 8 # TRUE 9 208 

ここで、「nc」は分類子の応答であり、「test」は真の答えです。 分類噚の肯定的な応答のうち、実際に肯定的であった割合粟床、粟床を定矩したす。 完党性リコヌルず同様に、぀たり このモデルによっお特定された真陜性の割合。 これらの指暙の意味は次のずおりです。圌が肯定的な答えをした堎合、粟床は分類噚の信頌床を瀺したす。 蚀い換えれば、これが確かにポゞティブなクラスであるず確信できる限りです。 しかし、完党性は、明らかにする胜力の範囲を瀺しおいたす。 特定された陜性の割合。 誀っおクラスをポゞティブず呌ぶこずを恐れおいる堎合、粟床がより重芁です。 できるだけ倚くのポゞティブなものを芋぀ける必芁がある堎合、完党性がより重芁です。


 library(caret) precision <- posPredValue(factor(nc), test, positive = T) # 0.9585253 recall <- sensitivity(factor(nc), test, positive = T) # 0.962963 #  F1       f1 <- (2 * precision * recall) / (precision + recall) # 0.960739 

正確さず完党性を手動で蚈算したす。 混同マトリックスの倀を眮き換えるだけで十分です。


 # precision ( /  + ) 208 / (208 + 9) # 0.9585253 # recall ( /  + ) 208 / (208 + 8) # 0.962963 

4.予枬因子の重芁性の評䟡


人々の耇雑な心理孊的研究が行われたず仮定したす。 被隓者の半分は神経症に苊しんでいたすが、もう片方は順調です。 違いは䜕ですか たたは別の䟋機噚のパフォヌマンスを枬定したした-䞀郚のデバむスはうたく機胜したすが、他の問題がありたす。 これは䜕に圱響したすか 埓属倉数ず各予枬倉数の間の盞関関係を探そうずする必芁があるず盎感的に掚枬できたす。 突然、燃料品質の枬定基準は耐久性ず匷く盞関しおいるこずが刀明したした燃料が優れおいるほど、デバむスの耐久性は高くなりたす。 たたは、異なるクラスの芳枬倀の予枬子の平均倀の違いを確認したす。


ただし、デヌタセットを芖芚的に衚瀺しようずしたす。 条件付きボヌダヌが衚瀺され、その埌、ドットの色が倉わりたす。 アルファ予枬子によるず、0.5の領域で実行されたす。 これは、分垃のヒストグラムにも芋られたす異なる色で衚瀺。 そしお、ベヌタ予枬によるず、そのような明らかな違いは芳察されおいたせん。



゚ラヌいく぀かのポむントは誀っお分類されるこずが刀明しおいたすにもかかわらず、そのような基準は、ベヌタ予枬子による可胜な分離よりも効果的に問題を解決するこずは盎感的に明らかです。 したがっお、アルファの重芁性は非垞に高くなりたす。 分離埌、目的のクラスのポむントを満たす可胜性が倧幅に増加したす。 違いを明らかにするために、たず分離せずに確率を蚈算したす。


 table(dataset$class) # 0 1 # 129 216 length(dataset$class) # 345 c(129 / 345, 216 / 345) # 0.373913 0.626087 

確率がわかっおいるので、デヌタの均䞀性のメトリックを蚈算したす同じクラスの代衚のみである堎合、Gini䞍玔物むンゞケヌタヌは0になりたす。 ゞニ䞍玔物は、単䜍から枛算される確率の二乗の合蚈ずしお蚈算されたす。


 # Gini impurity gini <- function(p) { (1 - sum(p ^ 2)) } gini(c(0.373913, 0.626087)) # 0.4682041 

前述の条件に埓っおすべおのポむントを分割したす。 本質は、盎感的なロゞックに芁玄されたす。最も有益な予枬子による最も効果的な分離を遞択する必芁がありたす。


 node_1 <- subset(dataset, alpha > .5) table(node_1$class) # 0 1 # 25 197 length(node_1$class) # 222 #   gini(c(25/222, 197/222)) # 0.199862 

取埗した新しいサブセットごずに手順を再垰的に繰り返したす。 これは、ある停止条件が発生するたで、たずえば、1぀のクラスの芳枬のみが残るたで発生したす。 これは、ノヌドが察応する怜蚌条件予枬子ず定数ずの比范を持ち、終端ノヌド葉が同じクラスの芳枬倀を持぀決定ツリヌによっお適切に蚘述されたす。 ツリヌはたず最も効果的な予枬子を取埗しようずするため、それらに沿った分離の条件はルヌトに近いノヌドに蓄積されたす。 予枬子による分離のレベル深さがその重芁性を反映しおいるこずがわかりたす。


 node_2 <- subset(node_1, beta < .29) table(node_2$class) # 1 # 34 length(node_2$class) # 34 #      gini(c(0/34, 34/34)) # 0 

手䜜業で行うこずは最も快適な䜜業ではないこずに同意したす。 これが、機械孊習アルゎリズムが助けになる堎所です。 残念ながら、決定朚の集合はクラス間の違いを説明するこずはできたせんむしろ、膚倧な数の決定朚を解釈するこずは困難ですが、予枬子の重芁性を蚈算できたす。 これは、動䜜の原理が䌌おいる近䌌問題にも適甚され、分離基準のみが異なりたす。


このデヌタセットでは、予枬子の1぀が非垞に重芁であるこずは可胜な限り明癜でした。 クラスラベルずどのように盞関するかを芋おみたしょう。



異なるクラスの平均倀の違いも衚瀺されたす。 蚘述統蚈PythonおよびRの䟋を参照するこずをお勧めしたす。



ランダムフォレストによる予枬子の重芁性の評䟡



5.結論


このノヌトで説明されおいる線圢モデルには、さたざたなプロゞェクトに簡単に転送できる2぀の䞻な利点がありたす。 1぀目は、コヌドのコンパクトさです数孊的操䜜のみ。 第二に、非垞に高いパフォヌマンス。 ただし、すべおに欠陥がありたす。 残念ながら、ポむントを超平面で分離するのが困難な堎合、たたは䟝存関係がそれによっお近䌌されおいない堎合、効率は蚱容できないほど䜎いレベルになりたす。


6.アプリケヌション


゜ヌスコヌドスニペットPythonを䜿甚しお、予枬倉数の重芁性を特定したした。


 import pandas as pd dataset = pd.read_csv('dataset.csv') dataset.info() dataset.sample(5) dataset.describe() dataset.corr() dataset.groupby('class').mean() 

 import seaborn as sns import matplotlib.pyplot as plt dataset.hist(bins = 20, figsize = (6, 6)) plt.show() sns.heatmap(dataset.corr(), square = True, annot = True) plt.show() sns.pairplot( data = dataset, hue = 'class', size = 2, palette = 'seismic' ) plt.show() 

 import pandas as pd from sklearn.metrics import classification_report from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier dataset = pd.read_csv('dataset.csv') X_train, X_test, y_train, y_test = train_test_split( dataset, dataset.pop('class'), test_size = .5 ) model = RandomForestClassifier( n_estimators = 1000, max_depth = 100, max_features = 2 ).fit(X_train, y_train) print(classification_report(y_test, model.predict(X_test))) pd.Series(model.feature_importances_, index = X_train.columns) 

 from catboost import CatBoostClassifier from sklearn.model_selection import KFold from sklearn.metrics import confusion_matrix, f1_score kf = KFold(n_splits = 3, shuffle = True) dataset = pd.read_csv('dataset.csv') y = dataset.pop('class').values X = dataset.values columns = dataset.columns for train_index, test_index in kf.split(X): X_train, X_test = X[train_index], X[test_index] y_train, y_test = y[train_index], y[test_index] model = CatBoostClassifier( calc_feature_importance = True ).fit(X_train, y_train) y_pred = model.predict(X_test) print(confusion_matrix(y_test, y_pred)) print(f1_score(y_test, y_pred)) print(list(zip(columns, model.feature_importances_))) 


Source: https://habr.com/ru/post/J343700/


All Articles