PHP机器学习与数据挖掘
引言
PHP虽然不是机器学习的主流语言,但借助数学扩展和纯PHP实现,可以完成许多数据挖掘和统计学习任务。本文从基础统计到经典ML算法,展示PHP在数据科学领域的应用能力。
数学基础与线性代数
机器学习的基础是数学运算,包括矩阵操作、向量运算和统计计算。
class VectorMath
{
public static function dot(array $a, array $b): float
{
$sum = 0;
foreach ($a as $i => $v) {
$sum += $v * $b[$i];
}
return $sum;
}
public static function add(array $a, array $b): array
{
$result = [];
foreach ($a as $i => $v) {
$result[$i] = $v + $b[$i];
}
return $result;
}
public static function subtract(array $a, array $b): array
{
$result = [];
foreach ($a as $i => $v) {
$result[$i] = $v - $b[$i];
}
return $result;
}
public static function scale(array $v, float $factor): array
{
return array_map(fn($x) => $x * $factor, $v);
}
public static function magnitude(array $v): float
{
return sqrt(array_sum(array_map(fn($x) => $x * $x, $v)));
}
public static function normalize(array $v): array
{
$mag = self::magnitude($v);
return $mag > 0 ? self::scale($v, 1 / $mag) : $v;
}
public static function cosineSimilarity(array $a, array $b): float
{
$dot = self::dot($a, $b);
$magA = self::magnitude($a);
$magB = self::magnitude($b);
if ($magA == 0 || $magB == 0) return 0;
return $dot / ($magA * $magB);
}
public static function euclideanDistance(array $a, array $b): float
{
$sum = 0;
foreach ($a as $i => $v) {
$sum += ($v - $b[$i]) ** 2;
}
return sqrt($sum);
}
public static function manhattanDistance(array $a, array $b): float
{
$sum = 0;
foreach ($a as $i => $v) {
$sum += abs($v - $b[$i]);
}
return $sum;
}
public static function hammingDistance(array $a, array $b): int
{
$count = 0;
foreach ($a as $i => $v) {
if ($v !== $b[$i]) $count++;
}
return $count;
}
}
class Matrix
{
private array $data;
private int $rows;
private int $cols;
public function __construct(array $data)
{
$this->data = $data;
$this->rows = count($data);
$this->cols = $this->rows > 0 ? count($data[0]) : 0;
}
public static function zeros(int $rows, int $cols): self
{
return new self(array_fill(0, $rows, array_fill(0, $cols, 0)));
}
public static function ones(int $rows, int $cols): self
{
return new self(array_fill(0, $rows, array_fill(0, $cols, 1)));
}
public static function identity(int $n): self
{
$data = [];
for ($i = 0; $i < $n; $i++) {
$data[$i] = array_fill(0, $n, 0);
$data[$i][$i] = 1;
}
return new self($data);
}
public static function fromColumnVector(array $v): self
{
return new self(array_map(fn($x) => [$x], $v));
}
public function get(int $row, int $col): float
{
return $this->data[$row][$col];
}
public function set(int $row, int $col, float $value): void
{
$this->data[$row][$col] = $value;
}
public function getData(): array { return $this->data; }
public function getRows(): int { return $this->rows; }
public function getCols(): int { return $this->cols; }
public function add(Matrix $other): self
{
$result = [];
for ($i = 0; $i < $this->rows; $i++) {
$row = [];
for ($j = 0; $j < $this->cols; $j++) {
$row[$j] = $this->data[$i][$j] + $other->data[$i][$j];
}
$result[$i] = $row;
}
return new self($result);
}
public function multiply(Matrix $other): self
{
if ($this->cols !== $other->rows) {
throw new \InvalidArgumentException("Matrix dimensions mismatch");
}
$result = [];
for ($i = 0; $i < $this->rows; $i++) {
$row = [];
for ($j = 0; $j < $other->cols; $j++) {
$sum = 0;
for ($k = 0; $k < $this->cols; $k++) {
$sum += $this->data[$i][$k] * $other->data[$k][$j];
}
$row[$j] = $sum;
}
$result[$i] = $row;
}
return new self($result);
}
public function transpose(): self
{
$result = [];
for ($i = 0; $i < $this->cols; $i++) {
$row = [];
for ($j = 0; $j < $this->rows; $j++) {
$row[$j] = $this->data[$j][$i];
}
$result[$i] = $row;
}
return new self($result);
}
public function map(callable $fn): self
{
$result = [];
foreach ($this->data as $i => $row) {
$result[$i] = array_map($fn, $row);
}
return new self($result);
}
public function toArray(): array
{
return $this->data;
}
}
// 统计学工具
class Statistics
{
public static function mean(array $values): float
{
return array_sum($values) / count($values);
}
public static function median(array $values): float
{
sort($values);
$count = count($values);
$mid = (int)floor($count / 2);
if ($count % 2 === 0) {
return ($values[$mid - 1] + $values[$mid]) / 2;
}
return $values[$mid];
}
public static function mode(array $values): array
{
$counts = array_count_values($values);
$maxCount = max($counts);
return array_keys(array_filter($counts, fn($c) => $c === $maxCount));
}
public static function variance(array $values, bool $sample = false): float
{
$mean = self::mean($values);
$squaredDiffs = array_map(fn($x) => ($x - $mean) ** 2, $values);
$divisor = $sample ? count($values) - 1 : count($values);
return array_sum($squaredDiffs) / $divisor;
}
public static function stdDev(array $values, bool $sample = false): float
{
return sqrt(self::variance($values, $sample));
}
public static function covariance(array $x, array $y): float
{
$meanX = self::mean($x);
$meanY = self::mean($y);
$n = count($x);
$sum = 0;
for ($i = 0; $i < $n; $i++) {
$sum += ($x[$i] - $meanX) * ($y[$i] - $meanY);
}
return $sum / ($n - 1);
}
public static function correlation(array $x, array $y): float
{
$cov = self::covariance($x, $y);
$stdX = self::stdDev($x, true);
$stdY = self::stdDev($y, true);
if ($stdX == 0 || $stdY == 0) return 0;
return $cov / ($stdX * $stdY);
}
public static function percentile(array $values, float $p): float
{
sort($values);
$n = count($values);
$rank = ($p / 100) * ($n - 1);
$lower = (int)floor($rank);
$upper = (int)ceil($rank);
if ($lower === $upper) return $values[$lower];
return $values[$lower] + ($rank - $lower) * ($values[$upper] - $values[$lower]);
}
public static function summary(array $values): array
{
sort($values);
return [
'count' => count($values),
'min' => min($values),
'max' => max($values),
'mean' => self::mean($values),
'median' => self::median($values),
'std' => self::stdDev($values, true),
'q1' => self::percentile($values, 25),
'q3' => self::percentile($values, 75),
'range' => max($values) - min($values),
'sum' => array_sum($values),
];
}
// 标准化(Z-score)
public static function standardize(array $values): array
{
$mean = self::mean($values);
$std = self::stdDev($values, true);
if ($std == 0) return array_fill(0, count($values), 0);
return array_map(fn($x) => ($x - $mean) / $std, $values);
}
// 最小-最大归一化
public static function minMaxScale(array $values, float $min = 0, float $max = 1): array
{
$vMin = min($values);
$vMax = max($values);
if ($vMax === $vMin) return array_fill(0, count($values), $min);
return array_map(fn($x) => ($x - $vMin) / ($vMax - $vMin) * ($max - $min) + $min, $values);
}
}
$data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
printf("Mean: %.2f\n", Statistics::mean($data));
printf("StdDev: %.2f\n", Statistics::stdDev($data, true));
printf("Correlation: %.2f\n", Statistics::correlation($data, [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]));
// K-Means 聚类
class KMeans
{
private int $k;
private int $maxIterations;
private array $centroids = [];
private array $labels = [];
public function __construct(int $k = 3, int $maxIterations = 100)
{
$this->k = $k;
$this->maxIterations = $maxIterations;
}
public function fit(array $samples): array
{
$n = count($samples);
$dims = count($samples[0]);
// 初始化质心(K-Means++ 优化)
$this->centroids = $this->initCentroids($samples);
for ($iter = 0; $iter < $this->maxIterations; $iter++) {
// 分配每个样本到最近的质心
$assignments = [];
foreach ($samples as $i => $sample) {
$minDist = INF;
$bestCluster = 0;
foreach ($this->centroids as $c => $centroid) {
$dist = VectorMath::euclideanDistance($sample, $centroid);
if ($dist < $minDist) {
$minDist = $dist;
$bestCluster = $c;
}
}
$assignments[$i] = $bestCluster;
}
// 更新质心
$newCentroids = array_fill(0, $this->k, array_fill(0, $dims, 0));
$counts = array_fill(0, $this->k, 0);
foreach ($samples as $i => $sample) {
$cluster = $assignments[$i];
for ($d = 0; $d < $dims; $d++) {
$newCentroids[$cluster][$d] += $sample[$d];
}
$counts[$cluster]++;
}
$changed = false;
for ($c = 0; $c < $this->k; $c++) {
if ($counts[$c] > 0) {
for ($d = 0; $d < $dims; $d++) {
$newCentroids[$c][$d] /= $counts[$c];
}
} else {
$newCentroids[$c] = $this->centroids[$c];
}
if (VectorMath::euclideanDistance($newCentroids[$c], $this->centroids[$c]) > 0.001) {
$changed = true;
}
}
$this->centroids = $newCentroids;
$this->labels = $assignments;
if (!$changed) break;
}
return $this->labels;
}
private function initCentroids(array $samples): array
{
$n = count($samples);
$centroids = [];
// 第一个随机选择
$centroids[] = $samples[array_rand($samples)];
for ($c = 1; $c < $this->k; $c++) {
$distances = [];
foreach ($samples as $i => $sample) {
$minDist = INF;
foreach ($centroids as $centroid) {
$dist = VectorMath::euclideanDistance($sample, $centroid);
if ($dist < $minDist) $minDist = $dist;
}
$distances[$i] = $minDist;
}
// 根据距离加权选择
$totalDist = array_sum($distances);
$rand = mt_rand() / mt_getrandmax() * $totalDist;
$cumulative = 0;
foreach ($distances as $i => $dist) {
$cumulative += $dist;
if ($cumulative >= $rand) {
$centroids[] = $samples[$i];
break;
}
}
}
return $centroids;
}
public function predict(array $sample): int
{
$minDist = INF;
$bestCluster = 0;
foreach ($this->centroids as $c => $centroid) {
$dist = VectorMath::euclideanDistance($sample, $centroid);
if ($dist < $minDist) {
$minDist = $dist;
$bestCluster = $c;
}
}
return $bestCluster;
}
public function getCentroids(): array { return $this->centroids; }
public function getLabels(): array { return $this->labels; }
// 轮廓系数评估
public function silhouetteScore(array $samples): float
{
$n = count($samples);
if ($n <= 1) return 0;
$totalScore = 0;
foreach ($samples as $i => $sample) {
$cluster = $this->labels[$i];
$sameClusterDists = [];
$otherClusterDists = [];
foreach ($samples as $j => $other) {
if ($i === $j) continue;
$dist = VectorMath::euclideanDistance($sample, $other);
if ($this->labels[$j] === $cluster) {
$sameClusterDists[] = $dist;
} else {
$otherClusterDists[$this->labels[$j]][] = $dist;
}
}
$a = !empty($sameClusterDists) ? array_sum($sameClusterDists) / count($sameClusterDists) : 0;
$b = INF;
foreach ($otherClusterDists as $dists) {
$meanDist = array_sum($dists) / count($dists);
if ($meanDist < $b) $b = $meanDist;
}
$max = max($a, $b);
$totalScore += $max > 0 ? ($b - $a) / $max : 0;
}
return $totalScore / $n;
}
}
// K-Means 示例
$samples = [];
for ($i = 0; $i < 100; $i++) {
$samples[] = [rand(0, 50) / 10, rand(0, 50) / 10];
}
for ($i = 0; $i < 100; $i++) {
$samples[] = [rand(50, 100) / 10, rand(50, 100) / 10];
}
$kmeans = new KMeans(2);
$labels = $kmeans->fit($samples);
printf("K-Means clusters: %d\n", count(array_unique($labels)));
printf("Silhouette score: %.4f\n", $kmeans->silhouetteScore($samples));
// K-最近邻 (KNN)
class KNearestNeighbors
{
private int $k;
private array $samples = [];
private array $labels = [];
private string $distanceMetric;
public function __construct(int $k = 3, string $distanceMetric = 'euclidean')
{
$this->k = $k;
$this->distanceMetric = $distanceMetric;
}
public function fit(array $samples, array $labels): void
{
$this->samples = $samples;
$this->labels = $labels;
}
public function predict(array $sample): mixed
{
$distances = [];
foreach ($this->samples as $i => $trainSample) {
$dist = match ($this->distanceMetric) {
'euclidean' => VectorMath::euclideanDistance($sample, $trainSample),
'manhattan' => VectorMath::manhattanDistance($sample, $trainSample),
'cosine' => 1 - VectorMath::cosineSimilarity($sample, $trainSample),
default => VectorMath::euclideanDistance($sample, $trainSample),
};
$distances[$i] = $dist;
}
asort($distances);
$neighbors = array_slice(array_keys($distances), 0, $this->k, true);
$votes = [];
foreach ($neighbors as $idx) {
$label = $this->labels[$idx];
$votes[$label] = ($votes[$label] ?? 0) + 1;
}
arsort($votes);
return array_key_first($votes);
}
public function predictBatch(array $samples): array
{
return array_map(fn($s) => $this->predict($s), $samples);
}
public function score(array $samples, array $labels): float
{
$correct = 0;
foreach ($samples as $i => $sample) {
if ($this->predict($sample) === $labels[$i]) {
$correct++;
}
}
return $correct / count($labels);
}
}
// KNN 示例
$trainSamples = [[1, 2], [2, 3], [3, 1], [6, 5], [7, 7], [8, 6]];
$trainLabels = ['A', 'A', 'A', 'B', 'B', 'B'];
$knn = new KNearestNeighbors(3);
$knn->fit($trainSamples, $trainLabels);
printf("KNN predict [2, 2]: %s\n", $knn->predict([2, 2]));
printf("KNN predict [7, 6]: %s\n", $knn->predict([7, 6]));
// 线性回归
class LinearRegression
{
private float $slope = 0;
private float $intercept = 0;
private float $r2 = 0;
public function fit(array $x, array $y): void
{
$n = count($x);
$meanX = Statistics::mean($x);
$meanY = Statistics::mean($y);
$num = 0;
$den = 0;
for ($i = 0; $i < $n; $i++) {
$num += ($x[$i] - $meanX) * ($y[$i] - $meanY);
$den += ($x[$i] - $meanX) ** 2;
}
$this->slope = $den != 0 ? $num / $den : 0;
$this->intercept = $meanY - $this->slope * $meanX;
// R² 计算
$ssRes = 0;
$ssTot = 0;
for ($i = 0; $i < $n; $i++) {
$pred = $this->predict($x[$i]);
$ssRes += ($y[$i] - $pred) ** 2;
$ssTot += ($y[$i] - $meanY) ** 2;
}
$this->r2 = $ssTot != 0 ? 1 - $ssRes / $ssTot : 0;
}
public function predict(float $x): float
{
return $this->slope * $x + $this->intercept;
}
public function getCoefficients(): array
{
return ['slope' => $this->slope, 'intercept' => $this->intercept, 'r2' => $this->r2];
}
public function predictBatch(array $x): array
{
return array_map(fn($v) => $this->predict($v), $x);
}
// 均方误差
public function mse(array $x, array $y): float
{
$n = count($y);
$sum = 0;
foreach ($y as $i => $actual) {
$pred = $this->predict($x[$i]);
$sum += ($actual - $pred) ** 2;
}
return $sum / $n;
}
}
// 线性回归示例
$x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$y = [2.1, 4.2, 6.1, 8.3, 10.2, 12.1, 14.3, 16.2, 18.1, 20.3];
$lr = new LinearRegression();
$lr->fit($x, $y);
$coeff = $lr->getCoefficients();
printf("Linear Regression: y = %.2fx + %.2f (R² = %.4f)\n", $coeff['slope'], $coeff['intercept'], $coeff['r2']);
printf("Predict x=11: %.2f\n", $lr->predict(11));
printf("MSE: %.4f\n", $lr->mse($x, $y));
// 多元线性回归 (梯度下降)
class MultipleLinearRegression
{
private array $weights = [];
private float $bias = 0;
private array $costHistory = [];
public function fit(array $samples, array $targets, float $learningRate = 0.01, int $epochs = 1000): void
{
$n = count($samples);
$features = count($samples[0]);
$this->weights = array_fill(0, $features, 0);
$this->bias = 0;
for ($epoch = 0; $epoch < $epochs; $epoch++) {
$predictions = $this->predictBatch($samples);
// 计算梯度
$dw = array_fill(0, $features, 0);
$db = 0;
for ($i = 0; $i < $n; $i++) {
$error = $predictions[$i] - $targets[$i];
for ($j = 0; $j < $features; $j++) {
$dw[$j] += $error * $samples[$i][$j];
}
$db += $error;
}
// 更新参数
for ($j = 0; $j < $features; $j++) {
$this->weights[$j] -= $learningRate * $dw[$j] / $n;
}
$this->bias -= $learningRate * $db / $n;
// 记录损失
if ($epoch % 100 === 0) {
$cost = $this->mse($samples, $targets);
$this->costHistory[$epoch] = $cost;
}
}
}
public function predict(array $sample): float
{
$sum = $this->bias;
foreach ($this->weights as $j => $w) {
$sum += $w * $sample[$j];
}
return $sum;
}
public function predictBatch(array $samples): array
{
return array_map(fn($s) => $this->predict($s), $samples);
}
public function mse(array $samples, array $targets): float
{
$n = count($targets);
$sum = 0;
foreach ($targets as $i => $target) {
$pred = $this->predict($samples[$i]);
$sum += ($target - $pred) ** 2;
}
return $sum / $n;
}
public function getWeights(): array { return $this->weights; }
public function getBias(): float { return $this->bias; }
public function getCostHistory(): array { return $this->costHistory; }
}
// 朴素贝叶斯分类器
class NaiveBayes
{
private array $priors = [];
private array $means = [];
private array $variances = [];
private array $classes = [];
public function fit(array $samples, array $labels): void
{
$this->classes = array_unique($labels);
$n = count($samples);
$features = count($samples[0]);
foreach ($this->classes as $class) {
$classSamples = [];
foreach ($samples as $i => $sample) {
if ($labels[$i] === $class) {
$classSamples[] = $sample;
}
}
$count = count($classSamples);
$this->priors[$class] = log($count / $n);
for ($f = 0; $f < $features; $f++) {
$values = array_column($classSamples, $f);
$this->means[$class][$f] = Statistics::mean($values);
$this->variances[$class][$f] = Statistics::variance($values, true) + 1e-9;
}
}
}
public function predict(array $sample): mixed
{
$bestClass = null;
$bestScore = -INF;
foreach ($this->classes as $class) {
$score = $this->priors[$class];
foreach ($sample as $f => $value) {
$mean = $this->means[$class][$f];
$variance = $this->variances[$class][$f];
$score += log($this->gaussianPdf($value, $mean, $variance));
}
if ($score > $bestScore) {
$bestScore = $score;
$bestClass = $class;
}
}
return $bestClass;
}
private function gaussianPdf(float $x, float $mean, float $variance): float
{
$exponent = - (($x - $mean) ** 2) / (2 * $variance);
return exp($exponent) / sqrt(2 * M_PI * $variance);
}
public function score(array $samples, array $labels): float
{
$correct = 0;
foreach ($samples as $i => $sample) {
if ($this->predict($sample) === $labels[$i]) {
$correct++;
}
}
return $correct / count($labels);
}
}
// 决策树
class DecisionTree
{
private ?array $tree = null;
private int $maxDepth;
private int $minSamples;
public function __construct(int $maxDepth = 10, int $minSamples = 2)
{
$this->maxDepth = $maxDepth;
$this->minSamples = $minSamples;
}
public function fit(array $samples, array $labels): void
{
$this->tree = $this->buildTree($samples, $labels, 0);
}
private function buildTree(array $samples, array $labels, int $depth): array
{
$labels = array_values($labels);
// 检查停止条件
if (count(array_unique($labels)) === 1 || $depth >= $this->maxDepth || count($samples) < $this->minSamples) {
return ['type' => 'leaf', 'value' => $this->mostCommon($labels)];
}
$nFeatures = count($samples[0]);
$bestGini = INF;
$bestSplit = null;
for ($f = 0; $f < $nFeatures; $f++) {
$values = array_unique(array_column($samples, $f));
sort($values);
for ($i = 0; $i < count($values) - 1; $i++) {
$threshold = ($values[$i] + $values[$i + 1]) / 2;
$gini = $this->giniIndex($samples, $labels, $f, $threshold);
if ($gini < $bestGini) {
$bestGini = $gini;
$bestSplit = ['feature' => $f, 'threshold' => $threshold];
}
}
}
if ($bestSplit === null || $bestGini >= 1) {
return ['type' => 'leaf', 'value' => $this->mostCommon($labels)];
}
$leftSamples = [];
$leftLabels = [];
$rightSamples = [];
$rightLabels = [];
foreach ($samples as $i => $sample) {
if ($sample[$bestSplit['feature']] <= $bestSplit['threshold']) {
$leftSamples[] = $sample;
$leftLabels[] = $labels[$i];
} else {
$rightSamples[] = $sample;
$rightLabels[] = $labels[$i];
}
}
if (empty($leftSamples) || empty($rightSamples)) {
return ['type' => 'leaf', 'value' => $this->mostCommon($labels)];
}
return [
'type' => 'node',
'feature' => $bestSplit['feature'],
'threshold' => $bestSplit['threshold'],
'left' => $this->buildTree($leftSamples, $leftLabels, $depth + 1),
'right' => $this->buildTree($rightSamples, $rightLabels, $depth + 1),
];
}
private function giniIndex(array $samples, array $labels, int $feature, float $threshold): float
{
$leftLabels = [];
$rightLabels = [];
foreach ($samples as $i => $sample) {
if ($sample[$feature] <= $threshold) {
$leftLabels[] = $labels[$i];
} else {
$rightLabels[] = $labels[$i];
}
}
$total = count($labels);
$leftWeight = count($leftLabels) / $total;
$rightWeight = count($rightLabels) / $total;
return $leftWeight * $this->giniImpurity($leftLabels)
+ $rightWeight * $this->giniImpurity($rightLabels);
}
private function giniImpurity(array $labels): float
{
$counts = array_count_values($labels);
$total = count($labels);
$impurity = 1;
foreach ($counts as $count) {
$p = $count / $total;
$impurity -= $p * $p;
}
return $impurity;
}
private function mostCommon(array $labels): mixed
{
$counts = array_count_values($labels);
arsort($counts);
return array_key_first($counts);
}
public function predict(array $sample): mixed
{
$node = $this->tree;
while ($node['type'] !== 'leaf') {
if ($sample[$node['feature']] <= $node['threshold']) {
$node = $node['left'];
} else {
$node = $node['right'];
}
}
return $node['value'];
}
public function predictBatch(array $samples): array
{
return array_map(fn($s) => $this->predict($s), $samples);
}
public function printTree(?array $node = null, int $depth = 0): void
{
if ($node === null) $node = $this->tree;
$indent = str_repeat(' ', $depth);
if ($node['type'] === 'leaf') {
printf("%s=> %s\n", $indent, $node['value']);
} else {
printf("%sif feature[%d] <= %.2f:\n", $indent, $node['feature'], $node['threshold']);
$this->printTree($node['left'], $depth + 1);
printf("%selse:\n", $indent);
$this->printTree($node['right'], $depth + 1);
}
}
}
// 特征工程
class FeatureExtractor
{
public static function polynomialFeatures(array $sample, int $degree = 2): array
{
$features = $sample;
$n = count($sample);
for ($d = 2; $d <= $degree; $d++) {
for ($i = 0; $i < $n; $i++) {
for ($j = $i; $j < $n; $j++) {
if ($d === 2) {
$features[] = $sample[$i] * $sample[$j];
}
}
}
}
return $features;
}
public static function oneHotEncode(array $categories, array $values): array
{
$encoded = [];
foreach ($values as $value) {
$row = array_fill(0, count($categories), 0);
$idx = array_search($value, $categories, true);
if ($idx !== false) {
$row[$idx] = 1;
}
$encoded[] = $row;
}
return $encoded;
}
public static function binarize(array $values, float $threshold): array
{
return array_map(fn($v) => $v > $threshold ? 1 : 0, $values);
}
}
// 分类器对比
$trainX = [[1, 2], [2, 1], [2, 3], [3, 2], [8, 7], [7, 8], [9, 7], [8, 9]];
$trainY = ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'];
$knn = new KNearestNeighbors(3);
$knn->fit($trainX, $trainY);
printf("KNN accuracy: %.2f\n", $knn->score($trainX, $trainY));
$nb = new NaiveBayes();
$nb->fit($trainX, $trainY);
printf("Naive Bayes accuracy: %.2f\n", $nb->score($trainX, $trainY));
$dt = new DecisionTree(5, 2);
$dt->fit($trainX, $trainY);
printf("Decision Tree accuracy: %.2f\n", $dt->score($trainX, $trainY));
$dt->printTree();
更多推荐


所有评论(0)