Есть ли более эффективный с точки зрения памяти способ использования combn для вычитания каждого столбца из каждого другого столбца в R?

Я пытаюсь вычесть каждый столбец из другого столбца в большой таблице R data.table, которая имеет 13125 столбцов и 90 строк.

Я продолжаю предыдущий вопрос, который касается этого для data.tables меньших размеров (Вычесть каждый столбец из каждого другого столбца в R data.table).

Моя проблема в том, что в настоящее время мне не хватает памяти для создания результирующей таблицы комбинаций столбцов data.table (для чего, похоже, требуется 59,0 ГБ).

Мой вопрос: есть ли более эффективный с точки зрения памяти способ вычисления различий столбцов с помощью combn или, возможно, другой функции для больших наборов данных?

Код, который я использовал:

# I have a data.table of 13125 columns and 90 rows, called data. 

# use combn to generate all possible pairwise column combinations (column + column),
# then within this apply a function to subtract the column value from its paired column value.
# this is done for each row, to produce a new datatable called res.

res <- as.data.table(combn(colnames(data), 2, function(x) data[[x[1]]] - data[[x[2]]]))

# take the pairwise column combinations and paste the pairing as the new column name

colnames(res) <- combn(colnames(data), 2, paste, collapse="_")

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


person fields    schedule 15.02.2019    source источник
comment
Вы просите МНОГО (около 86126250) попарных сравнений. Вы уверены, что это правильный поступок?   -  person Roman Luštrik    schedule 15.02.2019
comment
Количество парных комбинаций определяется как n!/(k!(n-k)!). В этом примере R не может даже вычислить это, так как factorial(13125) ошибки с value out of range in 'gammafn'. Поэтому я поддерживаю (решительно) утверждение @RomanLuštrik (мне пришлось обратиться к комбинаторному калькулятору бит-числа чтобы подтвердить свой номер). Вы уверены, что это действительно то, что вам нужно? Есть ли способ эвристически сократить пары, чтобы вы все еще находили искомое значение?   -  person r2evans    schedule 15.02.2019
comment
@r2evans Я только что сделал dim(combn(1:13125, 2)) и немного подождал.   -  person Roman Luštrik    schedule 16.02.2019
comment
@r2evans и Роман Луштрик, большое спасибо за ваши ответы. К сожалению, мне требуется такое количество сравнений. Для большего контекста мой набор данных содержит данные об экспрессии генов (13125 генов в виде столбцов и 90 образцов в виде строк). Моя мотивация состоит в том, чтобы рассчитать попарное отклонение экспрессии генов во всех образцах. В моем наборе данных также есть пропущенные значения, и я не смог найти пакет, который мог бы с этим справиться, поэтому я надеюсь вычислить его вручную. Мой конвейер заключается в том, чтобы затем возвести в квадрат эти сравнительные значения и суммировать итоги столбца, чтобы вычислить отклонение между парами генов.   -  person fields    schedule 18.02.2019


Ответы (1)


Согласно комментарию OP относительно следующего шага после разности столбцов, память будет более компактной, если вы также возведете в квадрат и суммируете итоги столбца во время расчета, чтобы в результате у вас был только вектор с 13 125 элементами, а не сохранение 13 125 * 90 *90 числовых вычитаемых значений. Быстрый и возможный подход - использовать RcppArmadillo:

colpairs.cpp (отнюдь не единственная реализация):

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace arma;

// [[Rcpp::export]]
rowvec colpairs(mat Z) {
    unsigned int i, j, k = Z.n_cols;
    colvec vi, vj, y;
    rowvec res(k);

    for (i=0; i<k; i++) {
        vi = Z.col(i);
        res[i] = 0;
        for (j=0; j<k; j++) {
            vj = Z.col(j);
            y = vi - vj;
            res[i] += as_scalar(y.t() * y);
        }
    }

    return res;
}

In R:

library(Rcpp)
library(RcppArmadillo)
sourceCpp("colpairs.cpp")

# #use a small matrix to check results
# set.seed(0L)
# nc <- 3; nr <- 3; M <- matrix(rnorm(nr*nc), ncol=nc)
# c(sum((M[,1]-M[,2])^2 + (M[,1]-M[,3])^2), sum((M[,3]-M[,2])^2 + (M[,2]-M[,3])^2), sum((M[,3]-M[,1])^2 + (M[,2]-M[,3])^2))
# colpairs(M)

set.seed(0L)
nc <- 13125
nr <- 90
M <- matrix(rnorm(nr*nc), ncol=nc)
colpairs(M)

ствол выход:

[1] 2105845 2303591 2480945 2052415 2743199 2475948 2195874 2122436 2317515  .....
person chinsoon12    schedule 20.02.2019