我有一个数据表dt
,例如:
a b c
[1] 1 2 3
[2] 2 3 4
[3] 3 4 5
[4] 4 5 6
我想将dt
的每个行中的值与向量vec
中的值相乘:
vec
1 0 0
我期望输出dt
得到以下结果:
a b c
[1] 1 0 0
[2] 2 0 0
[3] 3 0 0
[4] 4 0 0
我已经在for
循环中解决了这个问题。有没有更好的(矢量化)和更快的方法来解决此问题?有时我的数据表有成千上万的列,这就是循环变得很慢的原因。我还想保持数据表格式并避免转换。但是,最后,运行时间最快的解决方案对我来说很重要。
答案 0 :(得分:3)
在相对较大的5000x5000数据表上,使用for
在列上进行set
循环是我能找到的最快方法。这是我尝试的其他方法,取自Multiply rows of matrix by vector。方法按性能顺序排序,尽管在此规模下后两种方法几乎无法区分。
## sample data
nr = 5000
nc = 5000
set.seed(47)
raw_matrix = matrix(rpois(nr * nc, lambda = 10), nrow = nr)
vec = rpois(nc, lambda = 2)
## For loop with set
# reset the data table
x = as.data.table(raw_matrix)
t0 = Sys.time()
for (col in 1:ncol(x)) set(x, j = col, value = x[[col]] * vec[col])
(set_time = Sys.time() - t0)
# Time difference of 0.151 secs
## Transpose and multiply
# reset the data table
x = as.data.table(raw_matrix)
t0 = Sys.time()
x <- as.data.table(t(t(x) * vec))
# using as.data.table because setDT does not work on matrix
(transpose_time = Sys.time() - t0)
# Time difference of 0.614 secs
## Sweep
# reset the data table
x = as.data.table(raw_matrix)
t0 = Sys.time()
setDT(x <- sweep(x, MARGIN = 2, vec, "*"))
(sweep_time = Sys.time() - t0)
# Time difference of 1.81 secs
## Make Matrix method
# reset the data table
x = as.data.table(raw_matrix)
t0 = Sys.time()
setDT(x <- x * matrix(vec, dim(x)[1], length(vec), byrow = TRUE))
(make_matrix_time = Sys.time() - t0)
# Time difference of 1.88 secs
set
方法仅在您想要修改原始数据表时才有效。相反,如果您想保留原始文件并制作修改后的副本,则弗兰克(Frank)建议的方法效果很好--比修改原始文件的速度甚至稍微(当然,它需要更多的时间)内存):
## Create modified copy
z <- setDT(Map(`*`, x, vec))