3

我有一个矩阵(我猜在 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

我正在尝试在不使用 MatLab 中的任何现有函数的情况下创建 10 个交叉折叠验证,并且由于我对 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
4

2 回答 2

5

这是我对这个交叉验证的看法。我使用 magic(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 次。为此需要for循环。对于 5 个交叉折叠。我得到,在第一个 f

  1. 1st fold : 1 2 for test, 3:10 for train
  2. 第二折:3 4 用于测试,1 2 5:10 用于火车
  3. 第三折:5 6 用于测试,1:4 7:10 用于火车
  4. 4th fold : 7 8 for test, 1:6 9:10 for train
  5. 5th fold : 9 10 for test, 1:8 for train

以下代码是此过程的示例:

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
于 2012-09-27T22:41:35.957 回答
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))? 我认为这是一个从 1 到标签数组大小的随机整数(它可能是 0,请检查文档 - 如果是,请做简单的数学运算使其 1 < rand < 长度)
    4. 将该行添加到带有标签的新数据集中:newmat(index,:) = [data(randNum,:) labels(randNum) subsample]< 最后一列是 1-10 的子样本编号
    5. 从数据和标签中删除行:data(randNum,:) = []; same for labels<注意这将从矩阵中物理删除一行,这就是为什么我们必须使用while循环并检查长度> 0而不是for循环和简单索引的原因
    6. 增量计数器:index = index + 1; subsample = subsample + 1;
    7. 如果 subsample = 11,则再次将其设为 1。

最后,您应该有一个看起来几乎与原始数据完全相同的大型数据矩阵,但随机分配了“折叠标签”。

  1. 循环所有这些以及您的执行代码 k (10) 次。

编辑:以更易于访问的方式放置代码。注意它仍然是伪代码并且不完整!另外,您应该注意,这根本不是最有效的方法,但如果您不能使用 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 生成索引

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
于 2012-09-27T21:58:09.227 回答