2013-04-03 1 views
0

у меня есть матрица в Matlab, которая выглядит примерно так, за исключением тысячи строк:MATLAB: Сохранение количества случайных строк в матрице, которые удовлетворяют определенные условия

A = 

    5  6  7  8 
    6  1  2  3 
    5  1  4  8 
    5  2  3  7 
    5  8  7  2 
    6  1  3  8 
    5  2  1  6 
    6  3  2  1 

Я хотел бы Убирайтесь которая имеет три случайные строки с «5» в первом столбце и три случайные строки с «6» в первом столбце. Так что в этом случае выходной матрица будет выглядеть примерно так:

A = 

    5  6  7  8 
    6  1  2  3 
    5  2  3  7 
    6  1  3  8 
    5  2  1  6 
    6  3  2  1 

Строки должны быть случайными, а не только первые три или последние три в исходной матрице. Я не уверен, как начать это, поэтому любая помощь будет принята с благодарностью.

EDIT: Это самая успешная попытка, которую я получил до сих пор. Я нашел все строки с «5» в первой колонке:

BLocation = find(A(:,1) == 5); 
B = A(BLocation,:); 

Тогда я пытался использовать «randsample», как это, чтобы найти три случайных строк из B:

C = randsample(B,3); 

Но ' randsample 'не работает с матрицей.

Я также думаю, что это можно сделать немного более эффективно.

ответ

4

Вам необходимо запустить randsample на индексы строк, которые удовлетворяют условиям, то есть равенство в 5 или 6.

n = size(A,1); 

% construct the linear indices for rows with 5 and 6 
indexA = 1:n; 
index5 = indexA(A(:,1)==5); 
index6 = indexA(A(:,1)==6); 

% sample three (randomly) from each 
nSamples = 3; 
r5 = randsample(index5, nSamples); 
r6 = randsample(index6, nSamples); 

% new matrix from concatenation 
B = [A(r5,:); A(r6,:)]; 

Update: Вы можете также использовать find заменить оригинальную конструкцию индекса, так как ЮК предположил, что это будет быстрее (и оптимизировано!).

Bechmark (MATLAB R2012a)

A = randi(10, 1e8, 2); % 10^8 rows random matrix of 1-10 

tic; 
n = size(A,1); 
indexA = 1:n; 
index5_1 = indexA(A(:,1)==5); 
toc 

tic; 
index5_2 = find(A(:,1)==5); 
toc 

Elapsed time is 1.234857 seconds. 
Elapsed time is 0.679076 seconds. 
+0

'index5 = find (A (:, 1) == 5);' будет работать лучше, я думаю. – yuk

+0

@yuk, если вы получаете тот же результат, почему у вас есть накладные расходы на вызов find, поскольку вы можете напрямую индексировать 1: n, т. Е. Вектор индексов строк? Вышеупомянутая вы используете логическую индексацию только для вектора 1: n, который вы создаете аналитически. Если 'find' делает некоторую дополнительную оптимизацию производительности, я предполагаю, что она будет медленнее для больших матриц. Однако это не требует выделения нового вектора в памяти. – gevang

+0

@gevang Я проверил ваш код на скорость. Это не замедляет работу больших матриц. Мой код (ниже) быстрее для небольших матриц (около 10000 строк), но после этого время его запуска увеличивается. Я думаю, это потому, что я контактирую. –

2

Вы можете сделать это следующим образом:

desiredMat=[]; 
mat1=A(A(:,1)==5,:); 
mat1=mat1(randperm(size(mat1,1)),:); 
desiredMat=[desiredMat;mat1(1:3,:)]; 
mat1=A(A(:,1)==6,:); 
mat1=mat1(randperm(size(mat1,1)),:); 
desiredMat=[desiredMat;mat1(1:3,:)]; 

Приведенный выше код использует логическую индексацию. Вы также можете сделать это с помощью функции find (логическая индексация всегда быстрее, чем find).

+0

Да, этот код более чем в два раза быстрее, чем от @gevand. Первый 'randperm' является встроенной функцией. 'randsample' фактически вызывает' randperm'. Второй, вероятно, из-за прямой индексации. Я бы посоветовал не вырастить «желание Мать». Лучше создать 'mat2' и объединить их с' wishMat = [mat1 (1: 3, :); MAT2 (1: 3, :)]; '. Чуть быстрее. – yuk

Смежные вопросы