共用方式為


本文章是由機器翻譯。

測試回合

使用 C# 統一分類

James McCaffrey

下載代碼示例

James McCaffrey在機器學習 (毫升),分類是創建預測值,可採用離散、 非數位值的模型 (通常的某種形式的數學方程) 或一組規則的過程。例如,您可能想要預測基於他或她的投票記錄的國會議員的政黨 (民主黨人或共和黨人)。在模型訓練過程是發現 (對於一個數學方程模型) 的常量集或一組規則 (對於基於規則的模型),以便訓練資料與已知輸出依賴變數值時,計算的輸出密切與已知的輸出相匹配的過程。然後該模型可以用於預測新資料與未知的產出。

雖然有很多標準分類演算法和技術,包括樸素貝葉斯分類、 分類 logistic 回歸和神經網路分類器,對於某些問題自訂分類演算法很有用。本文介紹一種自訂技術,缺乏更好的名字,我叫共識分類。獲取什麼共識分類是一種感覺,看看這篇文章將走向何方是最好的方法是看一看該演示程式中圖 1

在行動中的協商一致意見分類
圖 1 在行動中的協商一致意見分類

該演示程式的目標是要創建一個模型,預測政黨,民主黨還是共和黨,美國的一名成員 眾議院的基於代表的投票記錄上的 16 立法法案。原始資料集由 100 個專案,其中每個對應一名代表和 17 的欄位組成。在每個專案的前 16 個欄位是其中字元"y"是一張贊成票,字元"n"是沒有投票權的票。每個專案的最後一個欄位是代表實際的政黨。例如,第一次的兩個數據專案是:

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

演示資料是知名的基準集稱為國會的投票記錄資料集的一個子集。完整的基準資料集有 435 項,其中一些有票值"?,"指示未知的投票或投棄權票。演示子集包括第一次 100 的專案,從套完整,沒有"?"票。此外,源資料集具有政黨的第一列 ; 我搬到最後一列,就方便得多,在程式設計時的党。

雖然它不是有必要瞭解什麼立法的條例草案的每個 16 票對應,每條條例草案的主題建議 16 以下短條款:殘疾嬰兒,水專案,採用預算、 醫生的收費、-薩爾瓦多、 學校宗教、 反衛星、 反尼加拉瓜政府分子、 mx 導彈、 移民法案、 合成燃料削減,教育開支,超級蘇,犯罪條例草案,免稅、 南非。

該演示程式將 100 項資料集拆分成 80 項集,用來訓練模型和 20 個專案的資料集,用來估計所生成模型的精度。協商一致意見分類模型由一組簡單的規則成員組成,如"如果代表投票 'y' 0 條例草案 》 和條例草案 》 3 'n' 和 'y' 條例草案 》 15,然後代表的是一位共和黨人。"在演示中,每個簡單的規則中的布林條件數目設置為 5,並且規則總數設置為 500。 此外,每個簡單的規則是需要至少 90%的準確率對適用于該規則的培訓資料項目目。

在幕後,訓練過程中生成的 500 的簡單規則。建立的模型後,該演示程式應用示範規則對訓練資料豐富了 93.75%的準確率。然後該模型應用於 20 個專案的測試集,從而產生 84.21%的準確率 — — 16 正確預測、 三個不正確的預測和在模型中 500 的規則都是適用的一個資料項目。

這篇文章假設你有至少中級程式設計技能和 ML 分類的基本知識。該演示編碼使用 C# 中,但你不應該有很多麻煩,到另一種語言,如Visual Basic.NET 或 Python 代碼進行重構。演示代碼有點太長,無法顯示其全部內容,但整個原始程式碼是在本文附帶的下載中提供 msdn.microsoft.com/magazine/msdnmag1114

程式的整體結構

演示程式,與一些 WriteLine 語句刪除和次要編輯為了節省空間,整體結構在圖 2。若要創建演示,推出Visual Studio創建新 C# 主控台應用程式和共識把它命名為­分類。演示有沒有重大的 Microsoft.NET 框架依賴關係,因此,任何較新版本的Visual Studio將工作。由範本生成的代碼載入後,解決方案資源管理器視窗我重命名檔 Program.cs 為更具描述性的 ConsensusProgram.cs 和Visual Studio自動重命名類程式,對我來說。

圖 2 程式的整體結構

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

所有程式邏輯都包含 Main 方法中。這個演示網站有兩個靜態説明器方法,MakeTrainTest 和 ShowData。分類邏輯包含在一個名為 ConsensusClassifier 的以單一程式定義的類。分類器公開公共的六種方法:一個單一的建構函式,RuleCount (模型中的簡單規則的實際數目)、 ComputeOutput (以使預測在創建模型後)、 火車 (以創建模型) 和重載的精度 (以計算正確預測的百分比)。

在 Main 方法中,演示程式硬編碼到一個陣列的陣列樣式字串矩陣的 100 項來源資料:

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" };
...

在非演示的情況下,您的資料可能會在一個文字檔中,您會將資料裝載到記憶體中用一種 helper 方法。來源資料拆分為訓練集和測試集,像這樣:

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

80/20 拆分百分比是硬編碼。0 值參數傳遞給方法 MakeTrainTest 是為以下注明連結化物件的種子值,以便列車試驗拆分可以隨機分配的資料項目。替代方法是使用一種階層式方法,以便訓練和測試矩陣中的民主黨人和共和黨人的資料項目的比例大約是整體的來源資料中的百分比相同。

演示使用此代碼創建的模型:

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

在這裡,我決定通過為每個規則中的布林條件數目和規則創建到建構函式中,並通過對訓練資料和最小精度的引用每個規則必須滿足方法列車的最大數目的值。許多開發人員希望將所有相關參數傳遞到建構函式 (犧牲大量的參數的建構函式)。在這裡,我通過與每個方法 (而忽視而任意尋找的調用介面) 最直接相關的值。

該演示程式最後通過計算並顯示了模型的準確性:

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);

第一個重載的精度返回只是正確分類的百分比。第二個重載的精度的回報,此外,數目正確,不正確和不適用的資料項目,凡非適用意味著,沒有一個模型的規則適用于特定資料項目。例如,假設條件數的參數被設置為 3,資料項目目之一的 vote0 = 'y' vote1 = 'y' 和 vote2 = '聯合國' 甚至 500 的規則,很可能為無規則採取這種組合的選票考慮。替代方法是設計方法精度,這樣非適用的資料項目目就不可能。做到這一種常見的方法是添加類似于,最終規則"。. 全新代表是一位民主黨人,"民主黨人所在的預設值,通常是最常見的因變數值。

該演示程式不使用模型來預測政黨的一名代表。預測政黨的一名代表投了贊成票"yes"法案 [0] 到 [7] 和"不"法案 [8] [15] 通過可能類似于以下內容:

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);

ComputeOutput 方法返回一個整數值,0 或 1,其中 0 表示共和黨,1 表明民主黨人。

一致性演算法

協商一致意見分類器的心是一個規則集。決定如何表示一個規則,兩個主要問題,以處理並建置規則。該演示程式作為整數陣列表示的規則。這項計畫最好的解釋使用一個具體的例子,如中所示圖 3。假設每個規則中的布林條件數目設置為三個。一個單一的規則會表示為具有七個單元的陣列。如果該陣列值 {3、 0、 8、 1、 15、 1、 0},然後規則都對應于"如果表決 [3] 是 0 和表決 [8] 是 1,表決 [15] 為 1,然後方是 0。規則集是泛型集合的規則的清單。

共識分類資料結構
圖 3 共識分類資料結構

0 和 1 的意思可以變化每列/票。該演示程式構造陣列字典集合,每列/投票一次。從零開始的整數 Id 分配給每個字串值他們你遇到的每個訓練資料中的列。舉個例子,在訓練資料中的投票 [0] [0] 列中,"n"是第一次遇到將指派給 0 和"y"是遇到下一步分配給 1。 但在列 [1],第一次遇到了"y"並為其分配為 0,"n"遇到第二次和分配給 1。

同樣,在訓練資料的列 [16] 中,最後一列,其中包含變數值"民主黨"和"共和主義"、"共和主義"第一次遇到如此為 0,和"民主黨"是 1。 字串到整數映射資訊存儲在名為 stringToInt,一個類成員陣列中所示圖 3。因此運算式 stringToInt [1] ["y"] 返回的從零開始的索引值為贊成票表決 [1],對於演示訓練資料,是 0。

以下是用於創建規則,用於定義分類模型的高級別的偽代碼:

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

一個具體的例子可以説明澄清。在主迴圈中,假設隨機播放的行 [0] 的訓練資料。接下來,假設 numConditions 已被設置為 3,並且三個隨機選定列的 [1] [2] 和 [15]。在培訓資料中,這些列包含值"y","n,"和"y"和因變數具有價值"共和主義"。陣列中查找的列的值-的-­字典集合,0,0 和 0。 因此,候選規則是一個整數陣列的值 {1,0,2、 0、 15、 0,0},可以被解釋為"如果列 1 0 和第 2 列是 0 且列 15 為 0,然後方是 0。

接下來,訓練資料中的 80 項進行掃描以查看是否候選規則符合最低的精度指標。請注意候選規則將正確的至少一個資料項目目 — — 用於創建規則的專案。然而,候選規則將不一定適用于所有的培訓專案。例如,從資料項目目 [0] 生成的候選規則 {1,0,2、 0、 15、 0,0} 不是適用于資料項目目 [1],因為列 [2] 具有值 1,而不是所需的 0。

一旦已經創建的規則集,輸出的一組給定的輸入資料確定由什麼可能被描述為計票。為每個資料項目的所有規則的規則集進行分析。假設,在這個演示中,規則集有 500 的規則。並且假設為一個資料項目,規則 220 預測共和黨政治黨派、 250 規則預測民主黨人,和 30 條的規定不適用。分類器將預測與資料關聯的人是一位民主黨人。換句話說,輸出是從規則集的預測一致。

幾個評論

在這篇文章提出了一種協商一致意見分類技術的動機來自于在前段時間工作的研究專案。尤其是,我試圖預測性別 — — 男性或女性 — — 的即時消息使用者基於變數,例如該區域的使用者,該使用者的年齡類別。我試著每一種標準的分類方法可以是,想一下使用現有毫升的工具,但我的方法都沒有能夠產生一種有效的預測模型,即使我的直覺是的資料包含足夠的資訊來產生信號。

我注意到使用樸素貝葉斯分類似乎是最好的我嘗試。樸素貝葉斯假設每個預測變數是數學上的獨立。儘管這一假設往往不是這樣的樸素貝葉斯有時工作得很好。對於我的問題,預測變數幾乎可以肯定聯繫在某種程度上,但我不能確定哪些變數有關。所以我決定要幾毫升技術部分用於創建在這篇文章中所描述的方法。最終,我才得以創建明顯比任何標準技術模型更準確的預測模型。

演示問題是一個二進位的分類問題,因為依賴變數可以是民主黨人或共和黨人。此外,所有的預測是二進位分類變數,因為他們要麼就是是或否。 分類可以處理多項式分類問題 (例如,民主黨人、 共和黨人、 獨立),也可以處理有兩個以上的值的分類預測的共識 (例如,是啊,不,缺席,投了棄權票)。在我的實驗中,尚不清楚如何有效共識分類時出現了問題是數值,作為隨著年齡的增長,和已經被冷藏到類別 (例如,年輕、 介質和老) 預測變數。

結合幾個規則或模型來生成一個分類結果通常被稱為集成毫升文字收集。毫升技術,用於生成許多簡單的規則的想法,這些有時被作為提高技術。讓我注意到在我測試回合的專欄中,我幾乎總是為其提供了毫升有一個堅實的研究基礎的技術。這篇文章是一個例外。這裡介紹的技術還沒有被正式研究或遭受嚴重的研究。幾個學術的同事把我任務有巨大的熊膽使用自訂的、 非傳統的 ML 技巧,但我通常有點刻薄的反應是我通常更關心得到比建立一個優雅的數學定理的結果。在我看來,使用標準毫升技術是最好的方法,初步探討毫升的問題,但傳統的技術當失敗時,創建一個自訂的解決方案有時可以有意想不到的效果。


James McCaffrey適合在雷德蒙的微軟研究院  他曾在幾個 Microsoft 產品包括 Internet Explorer 和冰。他可以在達成 jammc@microsoft.com

衷心感謝以下技術專家在微軟研究院對本文的審閱:馬西亞諾 Moreno 迪亞茲維亞、 埃爾伯特 · 墨菲、DavidRaskino 和愛麗森溶膠