#r #random
Вопрос:
У меня есть большая матрица данных со многими числовыми значениями (числами) в ней. Я хотел бы удалить 10% всех подсчетов. Так, например, матрица, которая выглядит следующим образом:
30 10 0 20
Сумма всех подсчетов здесь равна 60. 10% от 60 — это 6. Поэтому я хочу случайным образом удалить 6. Правильный вывод может быть:
29 6 0 19
(Как вы можете видеть, он удалил 1 из 30, 4 из 10 и 1 из 20). Не может быть отрицательных значений.
Как я мог запрограммировать это в R?
Ответ №1:
Вот способ. Он вычитает от 1 до положительных элементов матрицы до тех пор, пока не будет достигнуто определенное общее количество удаляемых элементов.
subtract_int lt;- function(X, n){ inx lt;- which(X != 0, arr.ind = TRUE) N lt;- nrow(inx) while(n gt; 0){ i lt;- sample(N, 1) if(X[ inx[i, , drop = FALSE] ] gt; 0){ X[ inx[i, , drop = FALSE] ] lt;- X[ inx[i, , drop = FALSE] ] - 1 n lt;- n - 1 } if(any(X[inx] == 0)){ inx lt;- which(X != 0, arr.ind = TRUE) N lt;- nrow(inx) } } X } set.seed(2021) to_remove lt;- round(sum(A)*0.10) subtract_int(A, to_remove) # [,1] [,2] #[1,] 30 6 #[2,] 0 18
Данные
A lt;- structure(c(30, 0, 10, 20), .Dim = c(2L, 2L))
Ответ №2:
Может быть, это поможет вам, по крайней мере, встать на правильный путь. Хотя это не более чем черновик:
randomlyRemove lt;- function(matrix) { sum_mat lt;- sum(matrix) while (sum_mat gt; 0) { sum_mat lt;- sum_mat - runif(1, min = 0, max = sum_mat) x lt;- round(runif(1, 1, dim(matrix)[1]), digits = 0) y lt;- round(runif(1, 1, dim(matrix)[2]), digits = 0) matrix[x,y] lt;- matrix[x,y] - sum_mat } return(matrix) }
Возможно, вам захочется поиграть с процессом генератора случайных чисел, чтобы получить более равномерно распределенные вычитания.
правка: добавлен раунд(цифры = 0), чтобы получать только целочисленные (размерные) значения, и изменено генерация случайных (размерных) значений, чтобы начинаться с 1 (не с нуля).
Ответ №3:
Я думаю, мы сможем заставить его работать с помощью sample
. Это решение намного компактнее.
Данные
A lt;- structure(c(30, 0, 11, 20), .Dim = c(2L, 2L)) sum(A) #gt; [1] 61
Логика
UseThese lt;- (1:length(A))[A gt; 0] # Choose indices to be modified because gt; 0 Sample lt;- sample(UseThese, sum(A)*0.1, replace = TRUE) # Draw a sample of indices A[UseThese] lt;- A[UseThese] - as.vector(table(Sample)) # Subtract handling repeated duplicate indices in the sample
Проверьте результат
A #gt; [,1] [,2] #gt; [1,] 28 8 #gt; [2,] 0 19 sum(A) # should be the value above minus 6 #gt; [1] 55
Одним из недостатков этого решения является то, что оно может привести к отрицательным значениям. Так что сверьтесь с:
any(A lt; 0) #gt; [1] FALSE