本文目录导读:

在PHP项目中实现交叉验证(Cross-Validation),通常需要结合机器学习库或手动实现,以下是几种常见方法:
使用 PHP-ML 库
PHP-ML 是一个流行的机器学习库,内置了交叉验证功能。
use Phpml\CrossValidation\RandomSplit; use Phpml\Classification\KNearestNeighbors; use Phpml\Metric\Accuracy; // 准备数据 $samples = [[1, 2], [3, 4], [5, 6], [7, 8]]; $labels = ['a', 'a', 'b', 'b']; // 随机分割数据为训练集和测试集(80/20) $dataset = new RandomSplit($samples, $labels, 0.2); // 训练模型 $classifier = new KNearestNeighbors(); $classifier->train($dataset->getTrainSamples(), $dataset->getTrainLabels()); // 预测 $predicted = $classifier->predict($dataset->getTestSamples()); // 计算准确率 $accuracy = Accuracy::score($dataset->getTestLabels(), $predicted); echo "Accuracy: " . $accuracy;
K-Fold 交叉验证
use Phpml\CrossValidation\KFold;
// 5折交叉验证
$kFold = new KFold($samples, $labels, 5, true);
foreach ($kFold as $index => $dataset) {
$classifier = new KNearestNeighbors();
$classifier->train($dataset->getTrainSamples(), $dataset->getTrainLabels());
$predicted = $classifier->predict($dataset->getTestSamples());
$accuracy = Accuracy::score($dataset->getTestLabels(), $predicted);
echo "Fold $index accuracy: $accuracy\n";
}
手动实现交叉验证
function crossValidation($data, $labels, $folds = 5) {
// 打乱数据
$indices = range(0, count($data) - 1);
shuffle($indices);
$dataShuffled = array_map(function($i) use ($data) {
return $data[$i];
}, $indices);
$labelsShuffled = array_map(function($i) use ($labels) {
return $labels[$i];
}, $indices);
// 分割数据为folds份
$foldSize = intval(count($data) / $folds);
$scores = [];
for ($i = 0; $i < $folds; $i++) {
$testStart = $i * $foldSize;
$testEnd = ($i + 1) * $foldSize;
// 训练集
$trainData = [];
$trainLabels = [];
// 测试集
$testData = array_slice($dataShuffled, $testStart, $foldSize);
$testLabels = array_slice($labelsShuffled, $testStart, $foldSize);
// 构建训练集
for ($j = 0; $j < count($dataShuffled); $j++) {
if ($j < $testStart || $j >= $testEnd) {
$trainData[] = $dataShuffled[$j];
$trainLabels[] = $labelsShuffled[$j];
}
}
// 训练和评估模型(这里使用简单的KNN)
$predicted = knnPredict($testData, $trainData, $trainLabels, 3);
$accuracy = calculateAccuracy($testLabels, $predicted);
$scores[] = $accuracy;
}
return [
'scores' => $scores,
'mean_score' => array_sum($scores) / count($scores)
];
}
function knnPredict($testSamples, $trainData, $trainLabels, $k = 3) {
$predictions = [];
foreach ($testSamples as $testSample) {
$distances = [];
foreach ($trainData as $index => $trainSample) {
$distances[] = [
'distance' => euclideanDistance($testSample, $trainSample),
'label' => $trainLabels[$index]
];
}
usort($distances, function($a, $b) {
return $a['distance'] <=> $b['distance'];
});
$nearestLabels = array_slice(array_column($distances, 'label'), 0, $k);
$predictions[] = array_search(max(array_count_values($nearestLabels)), array_count_values($nearestLabels));
}
return $predictions;
}
function euclideanDistance($a, $b) {
$sum = 0;
foreach ($a as $index => $value) {
$sum += pow($value - $b[$index], 2);
}
return sqrt($sum);
}
function calculateAccuracy($actual, $predicted) {
$correct = 0;
foreach ($actual as $index => $label) {
if ($label == $predicted[$index]) {
$correct++;
}
}
return $correct / count($actual);
}
// 使用示例
$data = [
[1.5, 2.0], [3.2, 4.1], [5.0, 5.5], [7.1, 8.0],
[2.0, 1.5], [4.5, 3.8], [6.0, 6.5], [8.2, 7.5]
];
$labels = ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B'];
$result = crossValidation($data, $labels, 4);
print_r($result);
分层交叉验证
function stratifiedKFold($data, $labels, $folds = 5) {
// 按类别分组
$groups = [];
foreach ($labels as $index => $label) {
$groups[$label][] = $index;
}
// 每个类别内部分割
$foldsData = array_fill(0, $folds, ['data' => [], 'labels' => []]);
foreach ($groups as $label => $indices) {
shuffle($indices);
$foldSize = intval(count($indices) / $folds);
for ($i = 0; $i < $folds; $i++) {
$start = $i * $foldSize;
$end = ($i == $folds - 1) ? count($indices) : ($i + 1) * $foldSize;
for ($j = $start; $j < $end; $j++) {
$idx = $indices[$j];
$foldsData[$i]['data'][] = $data[$idx];
$foldsData[$i]['labels'][] = $labels[$idx];
}
}
}
return $foldsData;
}
实际项目集成建议
class CrossValidator {
private $model;
private $samples;
private $labels;
public function __construct($model, $samples, $labels) {
$this->model = $model;
$this->samples = $samples;
$this->labels = $labels;
}
public function evaluate($folds = 10) {
$results = [];
// 使用PHP-ML的KFold
$kFold = new KFold($this->samples, $this->labels, $folds);
foreach ($kFold as $fold) {
$this->model->train(
$fold->getTrainSamples(),
$fold->getTrainLabels()
);
$predicted = $this->model->predict($fold->getTestSamples());
$results[] = [
'accuracy' => Accuracy::score($fold->getTestLabels(), $predicted),
'confusion_matrix' => $this->getConfusionMatrix(
$fold->getTestLabels(),
$predicted
)
];
}
return [
'folds' => $results,
'mean_accuracy' => array_sum(array_column($results, 'accuracy')) / count($results),
'std_accuracy' => $this->calculateStd(array_column($results, 'accuracy'))
];
}
private function getConfusionMatrix($actual, $predicted) {
$labels = array_unique(array_merge($actual, $predicted));
$matrix = [];
foreach ($labels as $actualLabel) {
foreach ($labels as $predictedLabel) {
$matrix[$actualLabel][$predictedLabel] = 0;
}
}
foreach ($actual as $i => $a) {
$matrix[$a][$predicted[$i]]++;
}
return $matrix;
}
private function calculateStd($values) {
$mean = array_sum($values) / count($values);
$variance = 0;
foreach ($values as $value) {
$variance += pow($value - $mean, 2);
}
return sqrt($variance / count($values));
}
}
// 使用示例
$validator = new CrossValidator(
new KNearestNeighbors(),
$samples,
$labels
);
$results = $validator->evaluate(5);
echo "Mean Accuracy: " . $results['mean_accuracy'];
echo "Std Accuracy: " . $results['std_accuracy'];
注意事项
- 数据预处理:确保数据格式正确,特征归一化
- 随机种子:设置随机种子以确保结果可重复
- 性能优化:大数据集时考虑使用缓存或分批处理
- 结果分析:不仅要看平均准确率,还要检查每折的方差
建议在小型项目中使用 PHP-ML 库,大型项目中考虑使用更专业的工具(如 Python 的 scikit-learn)进行模型评估,然后将结果集成到 PHP 应用中。