Il presente articolo è stato tradotto automaticamente.

Esecuzione di test

Classificazione dei consensi con C#

James McCaffrey

Scaricare il codice di esempio

James McCaffreyIn macchina (ML) di apprendimento, la classificazione è il processo di creazione di un modello (in genere un'equazione matematica di qualche tipo), o un insieme di regole che predice un valore che può assumere valori discreti, non numerici. Ad esempio, si potrebbe voler predire il partito politico (democratico o repubblicano) di un membro del Congresso basato sul suo voto record. Il modello di formazione è il processo di trovare il set di costanti (per un modello di equazione matematica) o un insieme di regole (per un modello basato su regole) in modo che quando ha presentato con i dati di allenamento con i noti valori di variabile dipendente dall'uscita, le uscite calcolate corrispondano strettamente le uscite note. Quindi il modello può essere utilizzato per fare le previsioni per i nuovi dati con uscite sconosciuti.

Anche se esistono molti algoritmi di classificazione standard e tecniche, tra cui la classificazione Naive Bayes, classificazione di regressione logistica e classificazione di rete neurale, per alcuni problemi di un algoritmo di classificazione personalizzato è utile. Questo articolo presenta una tecnica personalizzata che, per mancanza di un nome migliore, io chiamo la classificazione di consenso. Il modo migliore per avere un'idea di quale classificazione di consenso è e vedere dove è diretto questo articolo è quello di dare un'occhiata al programma demo in Figura 1.

classificazione di consenso in azione
Figura 1 classificazione di consenso in azione

L'obiettivo del programma demo è quello di creare un modello che predice il partito politico, democratico o repubblicano, di un membro degli Stati Uniti Camera dei rappresentanti sulla base voto record del rappresentante 16 bollette legislativa. Il set di dati grezzo è composto da 100 elementi, ognuno dei quali corrisponde a un rappresentante ed ha 17 campi. I primi 16 campi in ciascuna voce sono voti dove il carattere "y" è un voto sì e carattere "n" non è un voto. L'ultimo campo in ciascuna voce è vero partito politico del rappresentante. Ad esempio, sono i primi elementi di due dati:

n, y, y, n, y, y, n, n, n, n, n, n, y, y, y, y, democrat
n, y, n, y, y, y, n, n, n, n, n, y, y, y, n, y, republican

I dati demo sono un sottoinsieme di un insieme ben noto punto di riferimento chiamato l'insieme di dati record di voto del Congresso. Il set di dati completo di riferimento ha 435 articoli, alcuni dei quali hanno un valore di voto della "?," che indica un sconosciuto voto o astensione. Il sottoinsieme di demo composto dagli elementi primi 100, dal set completo, che non hanno alcun "?" voti. Inoltre, il set di dati di origine è il partito politico nella prima colonna; Ho spostato il partito per l'ultima colonna, che è molto più conveniente durante la programmazione.

Anche se non è necessario sapere quali bill legislativo ognuna delle 16 voti corrispondono a, l'argomento di ogni fattura è suggerito da 16 brevi termini seguenti: handicappati-infanti, acqua-progetto, adottare-bilancio, medico-tasse, el salvador, scuola-religione, anti-satellite, nicaraguense-contras, mx-missile, immigrazione-fattura, sponsorizzata-taglio, spesa per l'istruzione, citare in giudizio superfund, criminalità-fattura, duty free, sud-africa.

Il programma demo suddivide il set di dati di 100-elemento in un set di 80-item utilizzati per formare il modello e un set di dati 20-elemento utilizzato per stimare l'accuratezza del modello risultante. Un modello di classificazione del consenso consiste di un insieme di semplici regole come, "se il rappresentante ha votato 'y' sulla bolletta 0 e ' n' sulla bolletta 3 e 'y' sulla bolletta 15, poi il rappresentante è un repubblicano." Nella demo, il numero di condizioni booleane in ogni regola semplice è impostato su 5 e il numero totale di regole è impostato su 500. Inoltre, ogni regola semplice è necessario essere almeno il 90 per cento accurato sugli elementi di dati di addestramento per i quali è applicabile la regola.

Dietro le quinte, il processo di formazione generato 500 regole semplici. Dopo il modello è stato creato, il programma demo applicato le regole del modello ai dati formazione e ottenuto una precisione 93,75%. Allora il modello è stato applicato al set 20-elemento di prova, con conseguente 84.21 percento — 16 le previsioni corrette, tre previsioni errate e dati di un elemento dove nessuno dei 500 regole nel modello era applicabile.

Questo articolo si presuppone almeno intermedio di programmazione le abilità e le conoscenze di base di classificazione di ML. La demo è codificata utilizzando c#, ma non dovreste avere troppi problemi refactoring del codice per un'altra lingua, come Visual Basic .NET o Python. Il codice demo è un po' troppo lungo per presentare nella sua interezza, ma l'intero codice sorgente è disponibile nel download che accompagna questo articolo a msdn.microsoft.com/magazine/msdnmag1114.

Struttura generale del programma

La struttura generale del programma demo, con alcune modifiche WriteLine rimossi e minori di dichiarazioni per risparmiare spazio, è presentata Figura 2. Per creare la demo, lanciato Visual Studio e creato una nuova applicazione console c# e denominato esso il consenso­classificazione. La demo non ha nessun significativi dipendenze Microsoft .NET Framework, così qualsiasi versione relativamente recente di Visual Studio lavoro. Dopo aver caricato il codice generato dal modello, nella finestra Solution Explorer ho rinominato il file Program.cs per il ConsensusProgram.cs più descrittivo e Visual Studio rinominato automaticamente classe programma per me.

Figura 2 struttura generale del programma

using System;
using System.Collections.Generic;
namespace ConsensusClassification
{
  class ConsensusProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Begin consensus classification demo");
      Console.WriteLine("Goal is predict political party");
      string[][] allData = new string[100][];
      allData[0] = new string[] { "n", "y", "y", "n", "y", "y", "n", "n",
        "n", "n", "n", "n", "y", "y", "y", "y", "democrat" };
      allData[1] = new string[] { "n", "y", "n", "y", "y", "y", "n", "n",
        "n", "n", "n", "y", "y", "y", "n", "y", "republican" };
      // Etc.
      allData[99] = new string[] { "y", "n", "y", "n", "n", "y", "y", "y",
        "y", "y", "y", "n", "n", "n", "y", "y", "democrat" };
      Console.WriteLine("All data: ");
      ShowData(allData, 5, true);
      Console.WriteLine("Creating 80-20 train-test data");
      string[][] trainData;
      string[][] testData;
      MakeTrainTest(allData, 0, out trainData, out testData); // 0 = seed
      Console.WriteLine("Training data: \n");
      ShowData(trainData, 3, true);
      Console.WriteLine("Test data: \n");
      ShowData(testData, 3, true);
      int numConditions = 5; // Conditions per rule
      int maxNumRules = 500;
      double minAccuracy = 0.90; // Min % rule accuracy
      Console.WriteLine("Setting number conditions per rule = " + 
        numConditions);
      Console.WriteLine("Setting max number simple rules    = " + 
        maxNumRules);
      Console.WriteLine("Setting simple rule min accuracy   = " +
        minAccuracy.ToString("F2"));
      ConsensusClassifier cc =
        new ConsensusClassifier(numConditions, maxNumRules);
      Console.WriteLine("Starting training");
      cc.Train(trainData, minAccuracy);
      Console.WriteLine("Done");
      Console.WriteLine("Created " + cc.RuleCount() + " simple rules");
      double trainAcc = cc.Accuracy(trainData);
      Console.WriteLine("Accuracy on train data = " + 
        trainAcc.ToString("F4"));
      int numCorrect, numWrong, numUnknown;
      double testAcc = cc.Accuracy(testData, out numCorrect,
        out numWrong, out numUnknown);
      Console.WriteLine("Accuracy on test data  = " + 
        testAcc.ToString("F4"));
      Console.WriteLine("Number correct = " + numCorrect);
      Console.WriteLine("Number wrong   = " + numWrong);
      Console.WriteLine("Number unknown = " + numUnknown);
      Console.WriteLine("End consensus classification demo\n");
      Console.ReadLine();
    }
    static void MakeTrainTest(string[][] allData, int seed,
      out string[][] trainData, out string[][] testData) { . . }
    static void ShowData(string[][] rawData, int numRows,
      bool indices) { . . }
  } // Program
  public class ConsensusClassifier { . . }
} // ns

Tutta la logica del programma è contenuta nel metodo Main. La demo ha due metodi di supporto statici, MakeTrainTest e ShowData. La logica di classificazione è contenuta in una singola classe definito dal programma denominata ConsensusClassifier. Il classificatore espone sei metodi pubblici: un singolo costruttore, RuleCount (il numero effettivo di semplici regole nel modello), ComputeOutput (per fare previsioni dopo il modello è stato creato), treno (per creare il modello) e una precisione overload (per calcolare la percentuale di pronostici corretti).

Nel metodo Main, il demo programma hardcodes i dati di origine di 100-elemento in una matrice matrice di matrici-stile-stringa:

string[][] allData = new string[100][];
allData[0] = new string[] { "n", "y", "y", "n", "y", "y", "n", "n",
  "n", "n", "n", "n", "y", "y", "y", "y", "democrat" };
...

In uno scenario non demo, sarebbero probabilmente i dati in un file di testo e si sarebbe caricare i dati in memoria utilizzando un metodo di supporto. L'origine dati sono diviso in un set di training e un set di test, in questo modo:

string[][] trainData;
string[][] testData;
MakeTrainTest(allData, 0, out trainData, out testData);

Le percentuali di Spalato 80/20 sono hardcoded. L'argomento 0-valore passato al metodo MakeTrainTest è un valore di inizializzazione per un oggetto Math.Random in cui la scissione del treno-prova possibile assegnare elementi di dati in modo casuale. Un'alternativa è utilizzare un approccio stratificato in modo che le proporzioni di elementi di dati democratico e repubblicano nelle matrici di formazione e test sono più o meno lo stesso le percentuali nei dati di origine generale.

La demo crea il modello con questo codice:

int numConditions = 5;
int maxNumRules = 500;
double minAccuracy = 0.90;
ConsensusClassifier cc = 
  new ConsensusClassifier(numConditions, maxNumRules);
cc.Train(trainData, minAccuracy);

Qui, ho deciso di passare i valori per il numero di condizioni booleane in ogni regola ed il numero massimo di regole per creare al costruttore e passare un riferimento a dati di training e la minima precisione che ogni regola deve soddisfare al metodo treno. Molti sviluppatori preferiscono passare tutti i parametri relativi al costruttore (a scapito di un costruttore con un gran numero di parametri). Qui, passato valori più direttamente correlati a ogni metodo (a scapito di un'interfaccia chiamata aspetto piuttosto arbitraria).

Il programma demo si conclude con il calcolo e l'accuratezza del modello di visualizzazione:

double trainAcc = cc.Accuracy(trainData);
Console.WriteLine("Accuracy on train data = " + trainAcc.ToString("F4"));
int numCorrect, numWrong, numUnknown;
double testAcc = cc.Accuracy(testData, out numCorrect, out numWrong,
  out numUnknown);
Console.WriteLine("Accuracy on test data  = " + testAcc.ToString("F4"));
Console.WriteLine("Number correct = " + numCorrect);
Console.WriteLine("Number wrong   = " + numWrong);
Console.WriteLine("Number unknown = " + numUnknown);

La precisione prima di overload restituisce solo la percentuale delle classificazioni corretti. Il secondo overload accuratezza restituisce, in aggiunta, il numero corretto, scorretto e gli elementi di dati non applicabili, qualora non applicabili significa che nessuna delle regole del modello si applicano a un elemento particolare di dati. Ad esempio, se il parametro numero-di-condizioni era impostato su 3 e uno degli elementi di dati ha vote0 = 'y,' vote1 = 'y' e vote2 = 'n.' anche con 500 regole, è possibile che nessuno le regole per prendere questa combinazione di voti in considerazione. Alternativa, è possibile progettare metodo accuratezza, in modo che gli elementi di dati non applicabili non sono possibili. Un modo comune per farlo è quello di aggiungere una regola finale che assomiglia, ". . .else rappresentante è un democratico,"dove il democratico è un valore predefinito, che in genere è il valore più comune della variabile dipendente.

Il programma demo non utilizza il modello per predire il partito politico di un rappresentante. Predire il partito politico di un rappresentante che hanno votato "sì" sulle fatture [0] a [7] e "no" su fatture [8] e [15] potrebbe assomigliare a questo:

string[] newData = new string[] { "y", "y", "y", "y", "y", "y", "y", "y",
  "n", "n", "n", "n", "n", "n", "n", "n" };
int party = cc.ComputeOutput(newData);
Console.WriteLine("Predicted party = " + party);

Metodo ComputeOutput restituisce un valore intero, 0 o 1, dove 0 indica repubblicano e 1 indica democratico.

L'algoritmo di consenso

Il cuore del classificatore consenso è un insieme di regole. Le due questioni primarie da affrontare decide come rappresentare una regola e generando le regole. Il programma demo rappresenta una regola come una matrice di valori integer. Lo schema è meglio spiegato con un esempio concreto, come mostrato Figura 3. Supponiamo che il numero di condizioni booleane in ogni regola è impostato su tre. Una singola regola sarebbe rappresentata come una matrice con sette celle. Se la matrice ha avuto valori {3, 0, 8, 1, 15, 1, 0}, quindi la regola corrisponde a "Se il voto [3] è 0 e voto [8] è 1 e voto [15] è 1, poi partito è 0". La regola è un insieme di elenco generico delle regole.

consenso classificazione strutture di dati
Figura 3 consenso classificazione strutture di dati

Il significato di 0 e 1 può variare per ogni colonna/votazione. Il programma demo costruisce una matrice delle raccolte di dizionario, uno per ogni colonna/votazione. Integer in base zero IDs vengono assegnati per ogni valore di stringa come incontrarono in ogni colonna di dati di training. Ad esempio, nella colonna [0], per voto [0], in dati di training, "n" è rilevata prima e assegnate a 0 e "y" è rilevato successivamente e assegnate a 1. Ma nella colonna [1], "y" è rilevata prima e assegnate a 0 e "n" viene rilevata secondo e assegnato al 1.

Analogamente, nella colonna [16] i dati di addestramento, l'ultima colonna, che contiene la variabile dipendente i valori "democratici" e "repubblicano", "repubblicano" è rilevata in primo luogo quindi è 0 e "democratico" è 1. Le informazioni di mapping stringa per intero sono memorizzate in una matrice di membri di classe denominata stringToInt, come mostrato Figura 3. Così l'espressione stringToInt [1] ["y"] restituisce il valore di indice in base zero per un voto sì per votazione [1], che, per i dati di training demo, è 0.

Ecco il pseudo-codice alto livello per la creazione di regole che definiscono il modello di classificazione:

loop while numRules < maxRules && trial < maxTrials
  ++trial
  select a random row of training data
  select numConditions random columns of selected row
  create candidate rule from selected columns of selected row
  if candidate rule already in rule list, continue
  if candidate rule does not meet minimum accuracy, continue
  candidate rule is good so add rule to rule list
end loop

Un esempio concreto può aiutare a chiarire. Nel loop principale, supponiamo che casualmente viene selezionata la riga [0] i dati di allenamento. Successivamente, si supponga che numConditions è stato impostato su 3 e tre colonne casualmente selezionate sono [1] [2] e [15]. I dati di allenamento, queste colonne hanno valori "y" "n", e "y" e la variabile dipendente ha valore "repubblicano". I valori di colonna vengono cercati nella matrice-di-­raccolte di dizionario e sono 0, 0 e 0. Pertanto, la regola del candidato è una matrice di valori integer con valori {1, 0, 2, 0, 15, 0, 0}, che può essere interpretato come "Se la colonna 1 è 0 e la colonna 2 è 0 e colonna 15 è 0, allora partito è 0".

Successivamente, il 80 oggetti in dati di training vengono analizzati per vedere se la regola del candidato soddisfa il criterio di accuratezza minima. Si noti che la regola del candidato sarà corretta per l'elemento dati almeno un — l'elemento che è stato utilizzato per creare la regola. Tuttavia, la regola del candidato non sarà necessariamente applicabile a tutti gli elementi di formazione. Ad esempio, la regola di candidato che è stata generata da un elemento di dati [0] {1, 0, 2, 0, 15, 0, 0} non è applicabile all'elemento dati [1] perché colonna [2] ha valore 1, piuttosto che la necessaria 0.

Dopo aver creato il set di regole, l'output per un dato insieme di dati di input è determinato da ciò che potrebbe essere descritto come il conteggio dei voti. Per ogni elemento di dati, vengono analizzate tutte le regole nel set di regole. Supponiamo che, come nella demo, il set di regole ha 500 regole. E si supponga che per voce di uno dati, 220 delle regole predire un partito politico del repubblicano, 250 delle regole predire democratico e 30 delle norme non sono applicabili. Il classificatore sarebbe prevedere la persona associata ai dati è un democratico. In altre parole, l'output è un consenso delle previsioni da set di regole.

Alcuni commenti

La motivazione per la tecnica di classificazione consenso presentata in questo articolo è venuto da un progetto di ricerca che stavo lavorando su qualche tempo fa. In particolare, stavo cercando di predire il sesso, maschio o femmina — di un utente di messaggistica istantanea basato su variabili come la regione dell'utente, la categoria di età dell'utente e così via. Ho provato ogni tipo di classificazione standard di approccio che potrei pensare, utilizzando gli strumenti esistenti di ML, ma nessuno dei miei approcci sono stati in grado di generare un modello di previsione efficaci, anche se il mio intestino la sensazione era che i dati contenuti informazioni sufficienti per produrre un segnale.

Ho notato che usando la classificazione Naive Bayes sembrava essere il migliore dei miei tentativi. Naive Bayes presuppone che ogni variabile predittore è matematicamente indipendente. Anche se questa ipotesi spesso non è vera, Naive Bayes a volte funziona abbastanza bene. Per il mio problema, le variabili predittive sono stati quasi certamente legate in qualche modo, ma ero sicuro di quali variabili sono state legate. Così ho deciso di utilizzare parti di diverse tecniche di ML per creare l'approccio descritto in questo articolo. In definitiva, sono stato in grado di creare un modello di previsione che era significativamente più accurato rispetto a qualsiasi modello di norma tecnica.

Il problema di demo è un problema di classificazione binario perché la variabile dipendente può essere democratico o repubblicano. Inoltre, i predittori sono tutti binari variabili categoriche perché essi possono essere sia sì o no. Consenso classificazione può occuparsi di problemi di classificazione multinomiale (ad esempio, democratico, repubblicano, indipendente) e può gestire predittori categoriali che hanno più di due valori (ad esempio, sì, no, assenti, astenuti). Nei miei esperimenti, non era chiaro come classificazione consenso efficace è quando si presentavano problemi dove le variabili predittive sono numerici, come con l'età e sono state cestinate in categorie (ad esempio, giovani, media e vecchia).

Combinando diverse regole o modelli per generare un risultato di classificazione è spesso chiamato ensemble apprendimento nel vocabolario di ML. L'idea di generare molti semplici regole viene utilizzato nelle tecniche di ML, e questi a volte sono indicati come tecniche di amplificazione. Permettetemi di notare che nel mio Test eseguito colonna vi presento quasi sempre tecniche di ML che hanno una base solida di ricerca. Questo articolo è un'eccezione. La tecnica qui presentata non è stata studiata formalmente o sottoposta a ricerca seria. Molti colleghi accademici mi hanno preso al compito per aver fiele colossale di utilizzare tecniche di ML personalizzate, non tradizionali, ma mio solito un po ' snarky risposta è che io sono in genere più interessato a ottenere risultati che con la creazione di un teorema di matematica elegante. A mio avviso, utilizzando tecniche standard ML è il modo migliore per affrontare inizialmente un problema di ML, ma quando le tecniche tradizionali non riescono, creando una soluzione personalizzata può a volte essere sorprendentemente efficace.


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

Grazie ai seguenti esperti tecnici di Microsoft Research per la revisione di questo articolo: Marciano Moreno Diaz Covarrubias, Delbert Murphy, David Raskino e Alisson Sol