Я не могу заставить это работать, хотя это кажется довольно простым. Я хотел бы умножить каждую строку в матрице (или фрейме данных или данных) b на вектор a.
a <- data.table(t(1:4))
b <- matrix(data=2, nrow=3, ncol=4)
Желаемый результат (в форме матрицы, фрейма данных или данных):
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
Может ли кто-нибудь помочь мне, как это сделать (эффективно)?
Поскольку это некоторые данные из файла .txt, я должен это прочитать. И я знаю только, как это сделать в виде таблицы данных fread
или фрейма данных read_table
. Если бы я мог читать это как вектор, то это было бы для меня нормально.
Если вы знаете, что это однострочная таблица данных, сначала преобразуйте ее в вектор.
Советы респондентам: спрашивающего спрашивают «эффективно» - используйте microbenchmark
или другие инструменты тестирования производительности, чтобы оценить, насколько ваш эффективен по сравнению с другими; напишите my_name=function(a,b){...}
с вашим решением, чтобы его можно было легко протестировать на различных данных; тестировать на данных больше 3х4;
искать функцию развертки
Пожалуйста, опубликуйте лучший пример b
, который имеет разные данные в каждой строке, иначе люди не поймают ошибки при индексации, повторном использовании векторов и т. д. Кроме того, вы хотите, чтобы a
был вектором (строкой) или таблицей данных? Проще сделать a
вектором.
Опция 1: Использование возможностей data.table
:
Примечание: это работает, потому что номер столбца и значение совпадают для a
a[,lapply(.SD,function(x)(x*b[,x]))]
# V1 V2 V3 V4
#1: 2 4 6 8
#2: 2 4 6 8
#3: 2 4 6 8
Вариант 2: может быть:
t(t(b) * (as.matrix(a)[1,]))
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
ОБНОВИТЬ
Вариант №3: Для обработки десятичных / фактических значений в a
#Cases when `a` contains decimal values can be handled as
a <- data.table(t(c(1, 0.24, 3, 4)))
b <- matrix(data=2, nrow=3, ncol=4)
a[,lapply(V1:V4,function(i)(a[[i]]*b[,i]))]
# V1 V2 V3 V4
#1: 2 0.48 6 8
#2: 2 0.48 6 8
#3: 2 0.48 6 8
возможно, стоит упомянуть, что вы не используете матричное умножение, а повторно используете a
для поэлементного умножения с t(b)
.
Спасибо за ответ. Мне нравится ваше первое решение, поскольку оно является самым быстрым, однако я не совсем понимаю, как это похоже на цикл по строкам b. Особенно мне непонятно подмножество b с x b[,x]
. Вы можете мне это объяснить?
Можете ли вы объяснить, почему это работает: a <- data.table(t(c(1, 2, 3, 4, 5))) ; b <- matrix(data=1, nrow=10, ncol=5) ; a[,lapply(.SD,function(x)(x+b[,x]))]
, но если изменить данные a
на десятичный, он больше не работает: a <- data.table(t(c(1, 0.2, 3, 4, 5))) ; b <- matrix(data=1, nrow=10, ncol=5) ; a[,lapply(.SD,function(x)(x+b[,x]))]
@ Z117 Это решение было основано на умножении matrix/vector
на одно значение. Это был небольшой взлом, поскольку номер столбца и значение в столбце совпадали. Для каждого столбца было передано одно значение. Если вы хотите, чтобы это работало со значениями decimal
, тогда это должно быть: a[,lapply(V1:V4,function(i)(a[[i]]*b[,i]))]
@Moody_Mudskipper Вы абсолютно правы. Он был основан на умножении matrix/vector
с одним значением. Ваше решение тоже выглядит неплохо.
@Moody_Mudskipper На самом деле, я удивлен результатом скорости моего option#2
, который использует t
.
Я добавил в свое решение собственный тест с некоторыми дополнениями
Сравнительный анализ @Moody_Mudskipper действительно полезен. Это дает истинную картину. Хороший напарник.
dplyr::bind_rows(apply(b, 1, `*`, a))
V1 V2 V3 V4
1: 2 4 6 8
2: 2 4 6 8
3: 2 4 6 8
Сложность заключается в том, что ваш a
представляет собой таблицу данных. Если это на самом деле вектор, то все намного проще:
apply(b, 1, `*`, 1:4)
[,1] [,2] [,3]
[1,] 2 2 2
[2,] 4 4 4
[3,] 6 6 6
[4,] 8 8 8
Со своей стороны я бы использовал встроенный метод R для матричного умножения %*%
.
Учитывая вектор: [NB: data.table
- это нетvector
]
a <- c(1:4)
и учитывая матрицу:
b <- matrix(data=2, nrow=3, ncol=4)
Ваш результат определяется следующим образом:
output <- b %*% diag(a)
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
sweep
:sweep(b, 2, a, FUN = "*")
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
Это действительно неэффективный метод, поскольку R выполняет полное матричное умножение, что означает, что он выполняет много умножения на ноль и складывает полученный ноль ...
Ваша точка зрения верна, но актуальна только для больших матриц порядка миллионов строк. В данном случае @ Z117 этого не уточнил.
Нет. sweep
примерно в четыре раза быстрее на моей тестовой матрице 57 * 75, так что даже на маленьких матрицах есть выигрыш. Пользователь явно указал «эффективность», которую я приравняю к скорости и использованию памяти - создание большой пустой диагональной матрицы и последующее ее умножение неэффективно в обоих направлениях.
это очень интуитивно понятно, поэтому по-прежнему является ценным решением для интерактивного использования на небольшой и средней матрице
глядя на код sweep
, он сводится к созданию матрицы, повторяющей a
в виде строк перед умножением обоих объектов, обратный вызов можно резюмировать как b*aperm(array(a,rev(dim(b))))
, который быстрее, потому что мы пропускаем накладные расходы, он может быть оптимизирован в b*t(a)[rep_len(1,nrow(b)),]
для увеличения примерно на 30% скорость по сравнению с оригинальным sweep
b*rep(unlist(a),each=nrow(b))
# [,1] [,2] [,3] [,4]
# [1,] 2 4 6 8
# [2,] 2 4 6 8
# [3,] 2 4 6 8
или просто b*rep(a,each=nrow(b))
, если вы определяете a <- 1:4
Это просто векторизованное поэлементное умножение без преобразования из rep
.
редактировать:
Кажется, что репутация тормозит мое решение. Вот тест, в котором я включил опцию с предварительно вычисленным представлением и некоторые улучшения в опции развертки (взяв только соответствующие части из исходного кода).
a <- data.table(t(1:200))
b <- matrix(data=2, nrow=100000, ncol=200)
a_vec <- unlist(a)
rep_a <- rep(a_vec,each=nrow(b))
microbenchmark::microbenchmark(
mkr1 = a[,lapply(.SD,function(x)(x*b[,x]))],
mkr2 = t(t(b) * (as.matrix(a)[1,])),
mkr_update = a[,lapply(V1:V4,function(i)(a[[i]]*b[,i]))],
mm = b*rep(unlist(a),each=nrow(b)),
mm_cheat = b*rep_a,
regular_sweep = sweep(b,2,unlist(a),`*`),
regular_sweep2 = sweep(b,2,a_vec,`*`),
improved_sweepA1 = b*aperm(array(unlist(a),rev(dim(b)))),
improved_sweepA2 = b*aperm(array(a_vec,rev(dim(b)))),
improved_sweepB1 = b*a[rep_len(1,nrow(b)),],
improved_sweepB2 = b*t(a_vec)[rep_len(1,nrow(b)),],
unit = "relative",
times=50)
Unit: relative
expr min lq mean median uq max neval
mkr1 42.12228 44.15266 50.23959 46.35240 57.20280 65.07289 50
mkr2 114.58427 124.19653 125.25660 131.08677 124.17058 114.91137 50
mkr_update 1.00000 1.00000 1.00000 1.00000 1.00000 1.00000 50
mm 231.34331 223.74365 217.50145 225.91117 215.90765 165.64814 50
mm_cheat 13.38838 13.22556 14.94682 13.36649 12.95260 25.15564 50
regular_sweep 96.15758 124.26746 121.04428 128.67282 129.19407 119.20210 50
regular_sweep2 97.79001 124.69191 124.74650 134.64249 134.97407 107.47152 50
improved_sweepA1 96.57837 124.86189 116.93736 127.08909 124.92805 105.83318 50
improved_sweepA2 96.27737 122.49773 118.45262 128.13369 126.15029 106.58669 50
improved_sweepB1 214.95773 227.39523 226.04339 248.38553 232.50401 161.45341 50
improved_sweepB2 31.20967 32.61873 37.74552 33.70969 41.52149 55.93362 50
Это примерно в два раза дольше, чем решение sweep
в моем тесте для корпуса 75 * 57.
Тем не менее, я в 18 раз быстрее на этой маленькой матрице
Для более крупных операций rep
является причиной того, что он медленнее, мое решение становится в 7,5 раз быстрее, если rep(a,each=nrow(b)
предварительно вычислен, что является достойной стратегией в случаях использования, когда вычисления должны выполняться на нескольких матрицах одинаковых размеров.
Спасибо за ответы. Я протестировал предложенные выше решения по скорости (с фактическим размером моего вектора и матрицы), чтобы использовать наиболее эффективное:
a <- data.table(t(1:200))
b <- matrix(data=2, nrow=100000, ncol=200)
system.time(sweep(b, MARGIN=2, t(a), "*"))
# user system elapsed
# 0.31 0.06 0.39
system.time(a[,lapply(.SD,function(x)(x*b[,x]))])
# user system elapsed
# 0.2 0.0 0.2
#system.time(bind_rows(apply(b,1,`*`,a)))
#took 100+ so stopped it manually
system.time(t(t(b)*(as.matrix(a)[1,])))
# user system elapsed
# 0.31 0.05 0.36
system.time(apply(b, 1, `*`, 1:200))
# user system elapsed
# 1.20 0.11 1.31
system.time(b*rep(unlist(a),each=nrow(b)))
# user system elapsed
# 0.83 0.05 0.89
system.time(b*rep((1:200),each=nrow(b)))
# user system elapsed
# 0.36 0.06 0.42
Хорошая работа @ Z117. У нас есть полезная информация. Я удивлен скоростью моего option#2
, основанного на t
.
Почему у вашего "векторного"
a
таблица данных здесь? Это важно? Это имеет большое значение для того, как работает умножение, когда единица представляет собой таблицу данных. Сравните, например,a * b
с1:4 * b
. Это может быть причиной вашего разочарования.