Il presente articolo è stato tradotto automaticamente.

Esecuzione di test

Classificazione Probit in C#

James McCaffrey

Scaricare il codice di esempio

James McCaffreyClassificazione probit ("unità di probabilità") è una tecnica di apprendimento (ML) macchina che può essere utilizzata per fare previsioni in situazioni in cui la variabile dipendente da prevedere è binaria — che è, si può prendere uno dei due valori possibili. Classificazione probit è anche chiamato regressione probit e modellazione probit.

Classificazione probit è abbastanza simile alla classificazione di regressione logistica (LR). Le due tecniche si applicano per gli stessi tipi di problemi e tendono a dare risultati simili, e la scelta di utilizzare probit o LR classificazione dipende solitamente la disciplina in cui si sta lavorando. Probit è spesso utilizzato in economia e finanza, mentre LR è più comune in altri campi.

Per ottenere una comprensione di ciò che classificazione probit è, Guarda il programma demo in Figura 1.

classificazione Probit in azione
Figura 1 classificazione Probit in azione

La demo utilizza, probit per creare un modello che prevede che se un paziente ospedale morirà, basata su età, sesso e i risultati di un test di rene. I dati sono completamente artificiali. È il primo elemento di dati grezzi:

48.00   +1.00   4.40   0

I dati grezzi è composto da 30 elementi. Sesso è codificato come -1 per maschio e + 1 per donna. La variabile di predire, morì, è nell'ultima colonna ed è codificata come 0 = false (quindi la persona sopravvissuta) e 1 = true. Così, il primo elemento di dati indica una femmina di 48 anni con un punteggio di rene di 4,40 che sopravvissero. La demo comincia normalizzando i dati di età e rene, così che tutti i valori hanno all'incirca la stessa grandezza. Il primo elemento di dati, dopo la normalizzazione, è:

-0.74   +1.00   -0.61   0.00

Valori normalizzati inferiore a 0,0 (qui, rene ed età punteggio) sono sotto la media e valori superiori a 0.0 sono sopra la media.

L'origine dati sono poi casualmente suddiviso in una serie di formazione 24-elemento per creare il modello e un test la sei-elemento per stimare l'accuratezza del modello quando applicato ai nuovi dati con risultati sconosciuti.

Il programma demo crea quindi un modello probit. Dietro le quinte, la formazione viene eseguita utilizzando una tecnica chiamata ottimizzazione simplex, con il numero massimo di iterazioni impostato su 100. Dopo l'allenamento, vengono visualizzati i pesi che definiscono il modello {-4.26 2,30,-1.29, 3,45}.

Il primo valore di peso,-4.26, è una costante in generale e non si applica a qualsiasi variabili predittive specifiche. Il secondo peso, 2,30, si applica all'età; il terzo peso,-1.29, si applica al sesso; e il peso di quarto, 3,45, si applica al punteggio del rene. Pesi positivi, come quelli connessi con punteggio di rene e di età, significano valori più grandi del predittore indicano la variabile dipendente, è morto, sarà più grande — che è, più vicino al vero.

La demo consente di calcolare l'esattezza del modello sul set 24-voce di formazione (100 per cento corretto) e il set di prova (83,33%, o cinque corretto e uno sbagliato). Il più significativo di questi due valori è l'accuratezza del test. È una stima approssimativa dell'accuratezza complessiva del modello probit.

Questo articolo presuppone che hai almeno intermedio di programmazione le abilità e una conoscenza di base della classificazione di ML, ma non si assume che si sa nulla di classificazione probit. Il programma demo è codificato utilizzando c#, ma si dovrebbe essere in grado di rifattorizzare il demo per altri linguaggi .NET senza troppi problemi. Il codice demo è troppo lungo per presentare nella sua interezza, ma tutto il codice è disponibile nel download che accompagna questo articolo a msdn.microsoft.com/magazine/msdnmag1014. Tutto normale-il controllo degli errori è stato rimosso per mantenere le idee chiare.

Classificazione Probit comprensione

Un modo semplice per predire la morte da età, sesso e rene punteggio sarebbe per formare una combinazione lineare lungo le linee di:

died = b0 + (b1)(age) + (b2)(sex) + (b3)(kidney)

dove la b0, b1, b2, b3 sono pesi che in qualche modo devono essere determinati così i valori di output calcolate sui dati formazione strettamente corrispondono ai valori di variabile dipendente noto. Regressione logistica estende questa idea con una funzione di stima più complicata:

z = b0 + (b1)(age) + (b2)(sex) + (b3)(kidney)
died = 1.0 / (1.0 + e-z)

La matematica è molto profonda, ma la funzione di previsione, chiamata la funzione sigmoidea logistica, convenientemente restituisce sempre un valore compreso tra 0,0 e 1,0, che può essere interpretato come una probabilità. Classificazione probit utilizza una funzione di stima differenti:

z = b0 + (b1)(age) + (b2)(sex) + (b3)(kidney)
died = Phi(z)

La funzione Phi(z) viene chiamata la funzione di densità cumulativa normale standard (che è solitamente abbreviato CDF) e restituisce sempre un valore compreso tra 0,0 e 1,0. Il CDF è ingannevole, perché non non c'è nessun semplice equazione per esso. Il CDF per un valore di z è l'area sotto la funzione famosa curva a campana (la funzione gaussiana) dall'infinito negativo alla z.

Questo suona molto più complicato di quello che realmente è. Date un'occhiata al grafico in Figura 2. Il grafico mostra la funzione sigmoidea logistica e la funzione CDF tracciata parallelamente. Il punto importante è che per qualsiasi valore z, anche se le funzioni sottostanti sono molto diverse, entrambe le funzioni restituiscono un valore compreso tra 0,0 e 1,0 che può essere interpretato come una probabilità.

il grafico della funzione di densità cumulativa
Figura 2 il grafico della funzione di densità cumulativa

Così, dal punto di vista di uno sviluppatore la prima sfida è quello di scrivere una funzione che calcola il CDF per un valore di z. Non non c'è nessun semplice equazione per calcolare la CDF, ma ci sono decine di approssimazioni dall'aspetto esotico. Uno dei modi più comuni per approssimare la funzione CDF è per calcolare qualcosa chiamato la funzione erf (abbreviazione di errore funzione) utilizzando un'equazione chiamata A & S 7.1.26 e poi uso erf determinare CDF. Codice per la funzione CDF è presentata Figura 3.

Figura 3 la funzione CDF in c#

static double CumDensity(double z)
{
  double p = 0.3275911;
  double a1 = 0.254829592;
  double a2 = -0.284496736;
  double a3 = 1.421413741;
  double a4 = -1.453152027;
  double a5 = 1.061405429;
  int sign;
  if (z < 0.0)
    sign = -1;
  else
    sign = 1;
  double x = Math.Abs(z) / Math.Sqrt(2.0);
  double t = 1.0 / (1.0 + p * x);
  double erf = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) *
    t * Math.Exp(-x * x);
  return 0.5 * (1.0 + (sign * erf));
}

La seconda sfida durante la scrittura di codice di classificazione probit è per determinare che i valori per i pesi così quando ha presentato con i dati di training, l'output calcolato valori strettamente corrispondono ai valori di uscita noto. Un altro modo di guardare il problema è che l'obiettivo è ridurre al minimo l'errore tra valori calcolati e noto output. Questo è chiamato training del modello di ottimizzazione numerica.

Non non c'è nessun modo facile addestrare più classificatori ML, compresi i classificatori probit. Ci sono circa una dozzina di tecniche principali che si possono usare, e ogni tecnica ha decine di varianti. Tecniche di formazione comuni includono semplice gradiente discesa, retro-propagazione, Newton-Raphson, particella sciame optimization, ottimizzazione evolutiva e L-BFGS. Il programma demo utilizza una delle tecniche più semplici e più antica formazione — ottimizzazione simplex.

Ottimizzazione Simplex comprensione

Senza bloccare parlando, un simplesso è un triangolo. L'idea di ottimizzazione simplex è di iniziare con tre possibili soluzioni (quindi, "simplex"). Una soluzione sarà "migliore" (hanno il più piccolo errore), uno sarà "peggiori" (errore più grande), e il terzo è chiamato "altro". Ottimizzazione prossima, simplex crea tre nuove soluzioni potenziali, chiamati "allargato", "riflesso" e "contratta". Ognuna di queste viene confrontato con l'attuale soluzione peggiore, e se uno qualsiasi dei nuovi candidati è meglio (più piccolo errore), la soluzione peggiore è sostituita.

Ottimizzazione simplex è illustrata Figura 4. In un caso semplice in cui una soluzione costituita da due valori, come ad esempio (1,23, 4.56), si può pensare una soluzione come punto su (x, y) aereo. Il lato sinistro del Figura 4 illustrato come tre candidati nuove soluzioni sono generati dalla corrente migliore, peggiore e "altre" soluzioni.

ottimizzazione Simplex
Figura 4 ottimizzazione Simplex

In primo luogo, viene calcolato un centroide. Il baricentro è la media delle soluzioni migliori e altre. In due dimensioni, questo è un punto a metà strada tra i migliori e altri punti. Successivamente, una linea immaginaria creata, che inizia nel punto peggiore e si estende attraverso il centroide. Il candidato contratto è tra il peggio e il centroide punti. Il candidato riflesso è sulla linea immaginaria, passato il centroide. E il candidato espanso oltre il punto di riflesso.

In ogni iterazione di ottimizzazione simplex, se uno dei candidati espansi, riflessi o contratti è meglio che l'attuale peggiore soluzione, peggiore è sostituito da quel candidato. Se nessuno dei tre candidati generati sono meglio la soluzione peggiore, peggiore corrente e altre soluzioni vengono spostate verso la soluzione migliore punti da qualche parte tra la loro posizione attuale e la soluzione migliore, come mostrato nella parte destra della Figura 4.

Dopo ogni iterazione, si è formato un nuovo triangolo virtuale di "migliori altre peggiori", sempre più vicino e più vicino alla soluzione ottimale. Se uno snapshot di ogni triangolo è preso, quando guardò in sequenza, i triangoli spostamento simile a un blob a punta si spostano in tutto il piano in modo che assomiglia a un'ameba unicellulare. Per questo motivo, ottimizzazione simplex è talvolta chiamato ottimizzazione metodo ameba.

Ci sono molte variazioni di ottimizzazione simplex, che differiscono in quanto distano le soluzioni candidato contratta, riflessa e ampliato dal centroide attuale e l'ordine in cui le soluzioni del candidato sono controllate per vedere se sono meglio che l'attuale soluzione peggiore. La forma più comune di ottimizzazione simplex è chiamata l'algoritmo Nelder-Mead. Il programma demo utilizza una variante più semplice che non ha un nome specifico.

Per classificazione probit, ogni potenziale soluzione è un insieme di valori di peso. Figura 5 illustrato, nel frammento di codice, la variazione di ottimizzazione simplex utilizzate nel programma demo.

Figure 5 pseudocodice per l'ottimizzazione Simplex utilizzata nel programma Demo

randomly initialize best, worst other solutions
loop maxEpochs times
  create centroid from worst and other
  create expanded
  if expanded is better than worst, replace worst with expanded,
    continue loop
  create reflected
  if reflected  is better than worst, replace worst with reflected,
    continue loop
  create contracted
  if contracted  is better than worst, replace worst with contracted,
    continue loop
  create a random solution
  if  random solution is better than worst, replace worst,
    continue loop
  shrink worst and other toward best
end loop
return best solution found

Ottimizzazione simplex, come tutti gli altri algoritmi di ottimizzazione ML, ha Pro e contro. Tuttavia, è (relativamente) semplice da implementare e solitamente — anche se non sempre — funziona bene in pratica.

Il programma Demo

Per creare il programma demo, lanciato Visual Studio e c# console application programma modello selezionato e lo chiamarono ProbitClassification. La demo non ha significative Microsoft .NET Framework versione dipendenze, quindi qualsiasi versione relativamente recente di Visual Studio dovrebbe funzionare. Dopo aver caricato il codice del modello, nella finestra Solution Explorer ho rinominato il file Program.cs per ProbitProgram.cs e Visual Studio rinominato automaticamente il programma di classe.

Figura 6 inizio del codice Demo

using System;
namespace ProbitClassification
{
  class ProbitProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("\nBegin Probit Binary Classification demo");
      Console.WriteLine("Goal is to predict death (0 = false, 1 = true)");
      double[][] data = new double[30][];
      data[0] = new double[] { 48, +1, 4.40, 0 };
      data[1] = new double[] { 60, -1, 7.89, 1 };
      // Etc.
      data[29] = new double[] { 68, -1, 8.38, 1 };
...

All'inizio del codice demo è mostrato Figura 6. I dati fittizi sono hardcoded nel programma. In uno scenario non demo, i dati saranno memorizzati in un file di testo e si dovrebbe scrivere un metodo di utilità per caricare i dati in memoria. Successivamente, l'origine dati viene visualizzati utilizzando il metodo di supporto definito dal programma ShowData:

Console.WriteLine("\nRaw data: \n");
Console.WriteLine("       Age       Sex      Kidney   Died");
Console.WriteLine("=======================================");
ShowData(data, 5, 2, true);

Successivamente, vengono normalizzate colonne 0 e 2 di origine dati:

Console.WriteLine("Normalizing age and kidney data");
int[] columns = new int[] { 0, 2 };
double[][] means = Normalize(data, columns); // Normalize, save means & stdDevs
Console.WriteLine("Done");
Console.WriteLine("\nNormalized data: \n");
ShowData(data, 5, 2, true);

Il metodo Normalize Salva e restituisce i mezzi e le deviazioni standard di tutte le colonne in modo che quando nuovi dati viene rilevati, può essere normalizzato utilizzando gli stessi parametri utilizzati per il training del modello. Successivamente, i dati normalizzati sono divisa in un set di training (80 per cento) e set di test (20 per cento):

Console.WriteLine("Creating train (80%) and test (20%) matrices");
double[][] trainData;
double[][] testData;
MakeTrainTest(data, 0, out trainData, out testData);
Console.WriteLine("Done");
Console.WriteLine("\nNormalized training data: \n");
ShowData(trainData, 3, 2, true);

Si potrebbe voler parametrizzare il metodo MakeTrainTest di accettare la percentuale di elementi da inserire nel set di training. Successivamente, un oggetto definito dal programma probit classificatore viene creata un'istanza:

int numFeatures = 3; // Age, sex, kidney
Console.WriteLine("Creating probit binary classifier");
ProbitClassifier pc = new ProbitClassifier(numFeatures);

E poi il classificatore probit è addestrato, usando simplex ottimizzazione per trovare i valori per i pesi in modo che calcolati valori di output corrispondano strettamente i valori di output noti:

int maxEpochs = 100; // 100 gives a representative demo
Console.WriteLine("Setting maxEpochs = " + maxEpochs);
Console.WriteLine("Starting training");
double[] bestWeights = pc.Train(trainData, maxEpochs, 0);
Console.WriteLine("Training complete");
Console.WriteLine("\nBest weights found:");
ShowVector(bestWeights, 4, true);

Il programma demo conclude calcolando l'esattezza della classificazione del modello dati di training e i dati di prova:

...
  double testAccuracy = pc.Accuracy(testData, bestWeights);
  Console.WriteLine("Prediction accuracy on test data = 
    " + testAccuracy.ToString("F4"));
  Console.WriteLine("\nEnd probit binary classification demo\n");
  Console.ReadLine();
} // Main

La demo non rende un pronostico per dati inediti. Fare una previsione potrebbe apparire come:

// Slightly older, male, higher kidney score
double[] unknownNormalized = new double[] { 0.25, -1.0, 0.50 };
int died = pc.ComputeDependent(unknownNormalized, bestWeights);
if (died == 0)
  Console.WriteLine("Predict survive");
else if (died == 1)
  Console.WriteLine("Predict die");

Questo codice si presuppone che le variabili indipendenti x — età, sesso e rene punteggio — sono stati normalizzati utilizzando i mezzi e le deviazioni standard dal processo di normalizzazione dei dati formazione.

Classe ProbitClassifier

La struttura complessiva della classe ProbitClassifier è presentata Figura 7. La definizione di ProbitClassifier contiene una classe nidificata denominata soluzione. Tale sub-classe deriva dall'interfaccia IComparable affinché una matrice di tre oggetti di soluzione può essere ordinata automaticamente per dare le soluzioni migliori, altre e peggiori. Normalmente non mi piace fantasia tecniche di codifica, ma in questa situazione il beneficio supera leggermente la complessità aggiunta.

Figura 7 la classe di ProbitClassifier

public class ProbitClassifier
{
  private int numFeatures; // Number of independent variables
  private double[] weights; // b0 = constant
  private Random rnd;
  public ProbitClassifier(int numFeatures) { . . }
  public double[] Train(double[][] trainData, int maxEpochs, int seed) { . . }
  private double[] Expanded(double[] centroid, double[] worst) { . . }
  private double[] Contracted(double[] centroid, double[] worst) { . . }
  private double[] RandomSolution() { . . }
  private double Error(double[][] trainData, double[] weights) { . . }
  public void SetWeights(double[] weights) { . . }
  public double[] GetWeights() { . . }
  public double ComputeOutput(double[] dataItem, double[] weights) { . . }
  private static double CumDensity(double z) { . . }
  public int ComputeDependent(double[] dataItem, double[] weights) { . . }
  public double Accuracy(double[][] trainData, double[] weights) { . . }
  private class Solution : IComparable<Solution>
  {
    // Defined here
  }
}

Il ProbitClassifier ha due metodi di output. Metodo Compute­Output restituisce un valore compreso tra 0.0 e 1.0 e viene utilizzato durante l'allenamento per calcolare un valore di errore. Metodo ComputeDependent è un wrapper per ComputeOutput e restituisce 0 se l'output è minore o uguale a 0,5 o 1 se l'uscita è maggiore di 0,5. Questi valori restituiti vengono utilizzati per calcolare la precisione.

Conclusioni

Classificazione probit è una delle più antiche tecniche di ML. Poiché la classificazione probit è così simile alla classificazione di regressione logistica, saggezza comune è di utilizzare una tecnica o l'altra. Perché LR è leggermente più facile da implementare di probit, classificazione probit è usato meno spesso e nel tempo è diventato un po ' di un cittadino di ML seconda classe. Tuttavia, la classificazione probit è spesso molto efficace e può essere una preziosa aggiunta alla vostra toolkit di ML.


Dr. James McCaffrey lavora per la ricerca di Microsoft di Redmond, WA  Ha lavorato su diversi prodotti Microsoft, inclusi Internet Explorer e Bing. Dr. McCaffrey può essere raggiunto a jammc@microsoft.com.

Grazie ai seguenti esperti tecnici Microsoft Research per la revisione di questo articolo: Nathan Brown e Kirk Olynyk.