Как разбить данные на k-fold НЕ случайным образом в Matlab?

У меня есть набор данных, для простоты предположим, что он имеет 1000 образцов (каждый является вектором).

Я хочу разделить свои данные для перекрестной проверки, для обучения и тестирования, НЕ случайно 1, поэтому, например, если я хочу 4-кратную перекрестную проверку, я должен получить:

fold1: train = 1: 250; test = 251: 1000
fold2: train = 251: 500, test = [1: 250; 501: 1000]
fold3: train = 501: 750, test = [1: 500; 751: 1000]
fold4: train = 751: 1000, test = 1: 750

Мне известно о CVPARTITION, но AFAIK - он разбивает данные случайным образом, что это не то, что мне нужно.

Думаю, я могу написать для него код, но я подумал, что, вероятно, есть функция, которую я мог бы использовать.


(1) Данные уже перемешаны, и мне нужно иметь возможность легко воспроизвести эксперименты.


person amit    schedule 05.11.2013    source источник
comment
Я предполагаю, что вы знаете об этом, но если единственной целью является точно воспроизводимая работа, я бы рекомендовал установить rng для инициализации вашего случайного генератора перед рандомизацией выборки.   -  person Dennis Jaheruddin    schedule 05.11.2013


Ответы (3)


Вот функция, которая делает это в целом:

function [test, train] = kfolds(data, k)

  n = size(data,1);

  test{k,1} = [];
  train{k,1} = [];

  chunk = floor(n/k);

  test{1} = data(1:chunk,:);
  train{1} = data(chunk+1:end,:);

  for f = 2:k
      test{f} = data((f-1)*chunk+1:(f)*chunk,:);
      train{f} = [data(1:(f-1)*chunk,:); data(f*chunk+1:end, :)];
  end
end

Это не элегантный лайнер 1, но он довольно надежен, не требует k быть фактором количества образцов, работает с 2D-матрицей и выводит фактические наборы, а не индексы.

person Dan    schedule 05.11.2013
comment
Похоже, у меня сработало. Я не эксперт по Matlab, уточните, почему вы не включили первую итерацию в цикл for? - person amit; 05.11.2013
comment
Просто было меньше мысли не делать этого, потому что набор train всегда не пересекается, кроме первого раза. Хммм, хотя я думаю, что не в последний раз: / Если вы можете отредактировать его, чтобы он был в цикле, тогда, пожалуйста, сделайте :) - person Dan; 05.11.2013

Предположим, у вас есть k*n smaples, которые вы хотите разделить на k складки с n образцами в поезде и (k-1)*n в тесте (в вашем вопросе k = 4, n = 250).
Затем

 >> foldId = kron( 1:k, ones(1,n) );

foldId дает вам индекс обучающей кратности, к которой принадлежит каждая выборка.

Для свертки f вы можете получить показатели обучающей и тестовой выборок, используя

 >> trainIdx = find( foldId == f );
 >> testIdx  = find( foldId ~= f );

(Вы можете использовать логическую индексацию вместо find и немного ускорить процесс).

person Shai    schedule 05.11.2013

Чтобы разделить набор данных на k складки длины n, вы можете использовать:

f=arrayfun(@(x)struct('train',x*n+(1:n),'test',setdiff(1:n*k,x*n+(1:n))), 0:k-1);

где f - это массив структур с полями train и test, содержащими индексы для соответствующей складки. Например, для n=5 и k=3 и сбросить 2:

>> f(2).train
ans =
     6     7     8     9    10
>> f(2).test
ans =
     1     2     3     4     5    11    12    13    14    15

Вы даже можете напрямую извлекать данные. Допустим, ваши данные представляют собой 2D-матрицу из n*k строк.

E=arrayfun(...
@(x) struct('train', D(x*n+(1:n),:), ...
            'test',  D(setdiff(1:n*k, x*n+(1:n)),:)), 0:k-1)

Скажите, что ваши данные

D = [(1:15).^2; (1:15).^3].';

Для сгиба 2 E содержит:

>> E(2).train
ans =
          36         216
          49         343
          64         512
          81         729
         100        1000
>> E(2).test
ans =
           1           1
           4           8
           9          27
          16          64
          25         125
         121        1331
         144        1728
         169        2197
         196        2744
         225        3375
person Mohsen Nosratinia    schedule 05.11.2013