MATLAB:10倍交叉验证,不使用现有功能

时间:2012-09-27 21:29:32

标签: matlab machine-learning cross-validation

我有一个矩阵(我想在MatLab中你称之为结构)或数据结构:

  data: [150x4 double]
labels: [150x1 double]

这是我的matrix.data看起来像假设我加载我的文件名称为矩阵:

5.1000    3.5000    1.4000    0.2000
4.9000    3.0000    1.4000    0.2000
4.7000    3.2000    1.3000    0.2000
4.6000    3.1000    1.5000    0.2000
5.0000    3.6000    1.4000    0.2000
5.4000    3.9000    1.7000    0.4000
4.6000    3.4000    1.4000    0.3000
5.0000    3.4000    1.5000    0.2000
4.4000    2.9000    1.4000    0.2000
4.9000    3.1000    1.5000    0.1000
5.4000    3.7000    1.5000    0.2000
4.8000    3.4000    1.6000    0.2000
4.8000    3.0000    1.4000    0.1000
4.3000    3.0000    1.1000    0.1000
5.8000    4.0000    1.2000    0.2000
5.7000    4.4000    1.5000    0.4000
5.4000    3.9000    1.3000    0.4000
5.1000    3.5000    1.4000    0.3000
5.7000    3.8000    1.7000    0.3000
5.1000    3.8000    1.5000    0.3000

这是我的matrix.labels看起来像

 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1

我正在尝试创建10个交叉折叠验证而不使用MatLab中的任何现有函数,并且由于我非常有限的MatLab知识,我无法继续使用我的内容。任何帮助都会很棒。

这是我到目前为止所做的,我相信这可能不是matlab方式,但我对matlab很新。

function[output] = fisher(dataFile, number_of_folds)
    data = load(dataFile);
    %create random permutation indx
    idx = randperm(150);
    output = data.data(idx(1:15),:);
end

2 个答案:

答案 0 :(得分:5)

以下是我对此交叉验证的看法。我使用魔法创建虚拟数据(10)我也随机创建标签。想法如下,我们得到我们的数据和标签,并将它们与随机列结合起来。考虑遵循虚拟代码。

>> data = magic(4)

data =

    16     2     3    13
     5    11    10     8
     9     7     6    12
     4    14    15     1

>> dataRowNumber = size(data,1)

dataRowNumber =

     4

>> randomColumn = rand(dataRowNumber,1)

randomColumn =

    0.8147
    0.9058
    0.1270
    0.9134


>> X = [ randomColumn data]

X =

    0.8147   16.0000    2.0000    3.0000   13.0000
    0.9058    5.0000   11.0000   10.0000    8.0000
    0.1270    9.0000    7.0000    6.0000   12.0000
    0.9134    4.0000   14.0000   15.0000    1.0000

如果我们根据第1列对X进行排序,我们会随机对数据进行排序。这将给我们交叉验证随机性。然后接下来就是根据交叉验证百分比划分X.一个案例很容易实现这一点。让我们考虑%75%是火车案例,%25%是测试案例。我们这里的大小是4,然后3/4 =%75和1/4是%25。

testDataset = X(1,:)
trainDataset = X(2:4,:)

但是对于N交叉褶皱来说,实现这一点要困难得多。因为我们需要做N次。对于循环是必要的。适用于5个交叉折叠。我得到了,在第一个f

  1. 第1折:1 2为测试,3:10为火车
  2. 第二次折叠:3 4用于测试,1 2 5:10用于火车
  3. 第3折:5 6为测试,1:4 7:10为火车
  4. 第4折:7 8为测试,1:6 9:10为火车
  5. 第5折:9 10为测试,1:8为火车
  6. 以下代码是此过程的示例:

    data = magic(10);
    dataRowNumber = size(data,1);
    labels= rand(dataRowNumber,1) > 0.5;
    randomColumn = rand(dataRowNumber,1);
    
    X = [ randomColumn data labels];
    
    
    SortedData = sort(X,1);
    
    crossValidationFolds = 5;
    numberOfRowsPerFold = dataRowNumber / crossValidationFolds;
    
    crossValidationTrainData = [];
    crossValidationTestData = [];
    for startOfRow = 1:numberOfRowsPerFold:dataRowNumber
        testRows = startOfRow:startOfRow+numberOfRowsPerFold-1;
        if (startOfRow == 1)
            trainRows = [max(testRows)+1:dataRowNumber];
            else
            trainRows = [1:startOfRow-1 max(testRows)+1:dataRowNumber];
        end
        crossValidationTrainData = [crossValidationTrainData ; SortedData(trainRows ,:)];
        crossValidationTestData = [crossValidationTestData ;SortedData(testRows ,:)];
    
    end
    

答案 1 :(得分:3)

哈哈哈,对不起,没办法解决。我现在没有MATLAB,所以不能检查代码是否有错误。但这是一般的想法:

  1. 生成k(在您的情况下为10)子样本
    1. 在1处开始两个计数器并预先分配新矩阵:index = 1; subsample = 1; newmat = zeros("150","6")< 150是样本数,6 = 4宽数据+ 1宽标签+ 1我们稍后将使用
    2. 虽然您仍有数据:while ( length(labels) > 0 )
    3. 在剩余数据量中生成一个随机数:randNum = randi(length(labels))?我认为这是一个随机的int,从1到你的标签数组的大小(它可能是0,请检查文档 - 如果是,做简单的数学使它1< rand< length)
    4. 将该行添加到带有标签的新数据集中:newmat(index,:) = [data(randNum,:) labels(randNum) subsample]<最后一列是1-10
    5. 的子样本编号
    6. 从数据和标签中删除行:data(randNum,:) = []; same for labels<请注意,这将从矩阵中物理删除一行,这就是为什么我们必须使用while循环并检查长度> 0而不是for循环和简单索引
    7. 增量计数器:index = index + 1; subsample = subsample + 1;
    8. 如果subsample = 11,请再次将其设为1。
  2. 最后,您应该拥有一个看起来几乎与原始数据完全相同的大型数据矩阵,但随机分配了“折叠标签”。

    1. 遍历所有这些以及执行代码k(10)次。
    2. 编辑:以更易于访问的方式放置代码。注意它仍然是伪代码,并且不完整!此外,您应该注意,这不是最有效的方法,但如果您不能使用matlab函数,那么不应该太糟糕。

      for k = 1:10
      
      index = 1; subsample = 1; newmat = zeros("150","6");
      while ( length(labels) > 0 )
          randNum = randi(length(labels));
          newmat(index,:) = [data(randNum,:) labels(randNum) subsample];
          data(randNum,:) = []; same for labels
          index = index + 1; subsample = subsample + 1;
          if ( subsample == 11 )
              subsample = 1;
          end
      end
      
      % newmat is complete, now run code here using the sampled data 
      %(ie pick a random number from 1:10 and use that as your validation fold. the rest for training
      
      end
      

      编辑答案#2:

      另一种方法是创建一个与数据集一样长的载体

      foldLabels = zeros("150",1);
      

      然后,循环那么长(150),为随机索引分配标签!

      foldL = 1;
      numAssigned = 0;
      while ( numAssigned < 150 )
          idx = randi(150);
          % no need to reassign a given label, so check if is still 0
          if ( foldLabels(idx) == 0 )
              foldLabels(idx) = foldL;
              numAssigned++; % not matlab code, just got lazy. you get it
              foldL++;
              if ( foldL > 10 )
                  foldL = 1;
              end
          end
      end
      

      编辑答案#2.5

      foldLabels = zeros("150",1);
      for i = 1:150
          notChosenLabels = [notChosenLabels i];
      end
      foldL = 1;
      numAssigned = 0;
      while ( length(notChosenLabels) > 0 )
          labIdx = randi(length(notChosenLabels));
          idx = notChosenLabels(labIdx);
          foldLabels(idx) = foldL;
          numAssigned++; % not matlab code, just got lazy. you get it
          foldL++;
          if ( foldL > 10 )
              foldL = 1;
          end
          notChosenLabels(labIdx) = [];
      end
      

      编辑RANDPERM

      用randperm

      生成索引
      idxs = randperm(150);
      

      现在只需分配

      foldLabels = zeros(150,1);
      for i = 1:150
          foldLabels(idxs(i)) = sampleLabel;
          sampleLabel = sampleLabel + 1;
          if ( sampleLabel > 10 )
             sampleLabel = 1;
          end
      end