# 多粒子群优化的逻辑回归分类

James McCaffrey

Logistic 回归分析 （LR） 分类是机器学习的最基本形式之一。LR 分类的目标是创建一个模型，预测变量，可以在两个可能值之一。例如，您可能想要预测哪两位候选人的选民将选择 （"史密斯"= 0，"琼斯"= 1） 基于选民的年龄 (x1)、 性别 (2) 和年收入 (3)。

``````z = b0 + b1(x1) + b2(x2) + b3(x3)
Y = 1.0 / (1.0 + e^-z)
``````

10000 个元素数据集随机分成 8,000 项目训练集，用来创建 LR 模型和 2,000 项目拿测试集，用来训练后评价模型的准确性。该演示程序创建 LR 分类器，然后使用四个群，每个都有三个粒子来训练分类器。MSO 是一个迭代过程和迭代，maxEpochs，最大数目设置为 100。

## 程序的整体结构

``````using System;
namespace LogisticWithMulti
{
class LogisticMultiProgram
{
static void Main(string[] args)
{
Console.WriteLine("Begin demo");
int numFeatures = 5;
int numRows = 10000;
int seed = 0;
Console.WriteLine("Generating " + numRows +
" artificial data items with " + numFeatures + " features");
double[][] allData = MakeAllData(numFeatures, numRows, seed);
Console.WriteLine("Done");
Console.WriteLine("Creating train and test matrices");
double[][] trainData;
double[][] testData;
MakeTrainTest(allData, 0.80, seed, out trainData, out testData);
Console.WriteLine("Done");
Console.WriteLine("Training data: ");
ShowData(trainData, 4, 2, true);
Console.WriteLine("Test data: ");
ShowData(testData, 3, 2, true);
Console.WriteLine("Creating Logistic Regression classifier");
LogisticClassifier lc = new LogisticClassifier(numFeatures);
int numSwarms = 4;
int numParticles = 3;
int maxEpochs = 100;
Console.WriteLine("Setting numSwarms = " + numSwarms);
Console.WriteLine("Setting numParticles = " + numParticles);
Console.WriteLine("Setting maxEpochs = " + maxEpochs);
Console.WriteLine("\nStarting training");
double[] bestWeights = lc.Train(trainData, maxEpochs,
numSwarms, numParticles);
Console.WriteLine("Training complete");
Console.WriteLine("Best weights found:");
ShowVector(bestWeights, 4, true);
double trainAcc = lc.Accuracy(trainData, bestWeights);
Console.WriteLine("Accuracy on training data = " +
trainAcc.ToString("F4"));
double testAcc = lc.Accuracy(testData, bestWeights);
Console.WriteLine("Accuracy on test data = " +
testAcc.ToString("F4"));
Console.WriteLine("End demo");
} // Main
static double[][] MakeAllData(int numFeatures,
int numRows, int seed) { . . }
static void MakeTrainTest(double[][] allData,
double trainPct, int seed,
out double[][] trainData, out double[][] testData) { . . }
static void ShowData(double[][] data, int numRows,
int decimals, bool indices) { . . }
static void ShowVector(double[] vector, int decimals,
bool newLine) { . . }
} // Program
public class LogisticClassifier { . . }
} // ns
``````

Main 方法有很多 WriteLine 噪音。关键的调用语句都十分简单。合成数据已生成，像这样：

``````int numFeatures = 5;
int numRows = 10000;
int seed = 0; // Gives representative demo
double[][] allData = MakeAllData(numFeatures, numRows, seed);
``````

``````double[][] trainData;
double[][] testData;
MakeTrainTest(allData, 0.80, seed, out trainData, out testData);
``````

LR 模型是创建和培训这些语句：

``````LogisticClassifier lc = new LogisticClassifier(numFeatures);
int numSwarms = 4;
int numParticles = 3;
int maxEpochs = 100;
double[] bestWeights = lc.Train(trainData,
maxEpochs, numSwarms, numParticles);
``````

``````double trainAcc = lc.Accuracy(trainData, bestWeights);
double testAcc = lc.Accuracy(testData, bestWeights);
``````

## 理解 MSO 算法

``````for-each swarm
initialize each particle to a random position
end-for
for-each swarm
for-each particle in swarm
compute new velocity
use new velocity to compute new position
check if position is a new best
does particle die?
does particle move to different swarm?
end-for
end-for
return best position found
``````

MSO 算法的关键部分计算粒子的速度，是只是一组控件添加到一个粒子将搬哪里的值。例如，对于一个问题只是两个 x 尺寸，如果一个粒子处于 8.0 6.0） 和速度 1.0-2.0），粒子的新职位将在 9.0 4.0）。

``````v(t+1) = w * v(t) +
(c1 * r1) * (p(t) - x(t)) +
(c2 * r2) * (s(t) - x(t)) +
(c3 * r3) * (g(t) - x(t))
``````

``````v(t+1) = 0.7 * (-1.0, -3.0) +
(1.4 * 0.2) * ((10.0, 12.0) - (20.0, 30.0)) +
(1.4 * 0.2) * ((8.0, 9.0) - (20.0, 30.0)) +
(0.4 * 0.2) * ((5.0, 6.0) - (20.0, 30.0))
= 0.7 * (-1.0, -3.0) +
0.3 * (-10.0, -18.0) +
0.3 * (-12.0, -21.0) +
0.1 * (-15.0, -24.0)
= (-8.8, -16.2)
``````

``````x(t+1) = (20.0, 30.0) + (-8.8, -16.2)
= (11.2, 13.8)
``````

## 使用 MSO 执行 Logistic 回归分析

``````public double[] Train(double[][] trainData, int maxEpochs,
int numSwarms, int numParticles)
{
int dim = numFeatures + 1;
double minX = -10.0;
double maxX = 10.0;
MultiSwarm ms = new MultiSwarm(numSwarms, numParticles, dim);
...
``````

``````for (int i = 0; i < numSwarms; ++i)
{
for (int j = 0; j < numParticles; ++j)
{
Particle p = ms.swarms[i].particles[j];
p.error = Error(trainData, p.position);
p.bestError = p.error;
Array.Copy(p.position, p.bestPosition, dim);
...
``````

``````...
if (p.error < ms.swarms[i].bestError) // Swarm best?
{
ms.swarms[i].bestError = p.error;
Array.Copy(p.position, ms.swarms[i].bestPosition, dim);
}
if (p.error < ms.bestError) // Global best?
{
ms.bestError = p.error;
Array.Copy(p.position, ms.bestPosition, dim);
}
} // j
} // i
``````

``````int epoch = 0;
double w = 0.729; // inertia
double c1 = 1.49445; // particle
double c2 = 1.49445; // swarm
double c3 = 0.3645; // multiswarm
double pDeath = 1.0 / maxEpochs;
double pImmigrate = 1.0 / maxEpochs;
int[] sequence = new int[numParticles];
for (int i = 0; i < sequence.Length; ++i)
sequence[i] = i;
``````

``````while (epoch < maxEpochs)
{
++epoch;
// Optionally print best error here
for (int i = 0; i < numSwarms; ++i) // Each swarm
{
Shuffle(sequence);
for (int pj = 0; pj < numParticles; ++pj) // Each particle
{
int j = sequence[pj];
Particle p = ms.swarms[i].particles[j];
...
``````

``````for (int k = 0; k < dim; ++k)
{
double r1 = rnd.NextDouble();
double r2 = rnd.NextDouble();
double r3 = rnd.NextDouble();
p.velocity[k] = (w * p.velocity[k]) +
(c1 * r1 * (p.bestPosition[k] - p.position[k])) +
(c2 * r2 * (ms.swarms[i].bestPosition[k] - p.position[k])) +
(c3 * r3 * (ms.bestPosition[k] - p.position[k]));
if (p.velocity[k] < minX)
p.velocity[k] = minX;
else if (p.velocity[k] > maxX)
p.velocity[k] = maxX;
} // k
``````

``````for (int k = 0; k < dim; ++k)
{
p.position[k] += p.velocity[k];
if (p.position[k] < minX)
p.position[k] = minX;
else if (p.position[k] > maxX)
p.position[k] = maxX;
}
``````

``````p.error = Error(trainData, p.position); // Expensive
if (p.error < p.bestError) // New best position for particle?
{
p.bestError = p.error;
Array.Copy(p.position, p.bestPosition, dim);
}
``````

``````if (p.error < ms.swarms[i].bestError) // New best for swarm?
{
ms.swarms[i].bestError = p.error;
Array.Copy(p.position, ms.swarms[i].bestPosition, dim);
}
if (p.error < ms.bestError) // New global best?
{
ms.bestError = p.error;
Array.Copy(p.position, ms.bestPosition, dim);
}
``````

``````double p1 = rnd.NextDouble();
if (p1 < pDeath)
{
Particle q = new Particle(dim); // A replacement
q.error = Error(trainData, q.position);
Array.Copy(q.position, q.bestPosition, dim);
q.bestError = q.error;
``````

``````double pDeath = (maxProbDeath / maxEpochs) * epoch;
``````

``````if (q.error < ms.swarms[i].bestError) // Best swarm error by pure luck?
{
ms.swarms[i].bestError = q.error;
Array.Copy(q.position, ms.swarms[i].bestPosition, dim);
if (q.error < ms.bestError) // Best global error?
{
ms.bestError = q.error;
Array.Copy(q.position, ms.bestPosition, dim);
}
}
``````

``````...
ms.swarms[i].particles[j] = q;
} // Die
``````

``````double p2 = rnd.NextDouble();
if (p2 < pImmigrate)
{
int ii = rnd.Next(0, numSwarms); // rnd swarm
int jj = rnd.Next(0, numParticles); // rnd particle
Particle q = ms.swarms[ii].particles[jj]; // q points to other
ms.swarms[i].particles[j] = q;
ms.swarms[ii].particles[jj] = p; // the exchange
...
``````

``````...
if (q.error < ms.swarms[i].bestError) // Curr has new position
{
ms.swarms[i].bestError = q.error;
Array.Copy(q.position, ms.swarms[i].bestPosition, dim);
}
if (p.error < ms.swarms[ii].bestError) // Other has new position
{
ms.swarms[ii].bestError = p.error;
Array.Copy(p.position, ms.swarms[ii].bestPosition, dim);
}
} // Immigrate
``````

``````...
} // j - each particle
} // i - each swarm
} // while
return ms.bestPosition;
} // Train
``````

## 总结

Logistic 回归分析是机器学习分类最简单的形式之一。对于很多分类问题，LR 就不灵了。然而，很多毫升的从业人员，包括我在内，通常开始调查使用 LR，一个分类问题，然后使用更先进的技术，如有必要。