在Windows 7和Ubuntu 64位11.04的Revolution R 2.12.2中,我有一个超过100K行和超过100列的数据帧,我为每个派生了~5列(sqrt,log,log10等)原始列并将它们添加到同一数据框中。如果没有使用foreach和%do%的并行性,这可以正常工作,但速度很慢。当我尝试将它与foreach和%dopar%并行化时,它将不会访问全局环境(以防止竞争条件或类似的情况),因此我无法修改数据框,因为数据框对象“找不到”。 / p>
我的问题是如何让这更快?换句话说,如何并行化列或转换?
简化示例:
require(foreach)
require(doSMP)
w <- startWorkers()
registerDoSMP(w)
transform_features <- function()
{
cols<-c(1,2,3,4) # in my real code I select certain columns (not all)
foreach(thiscol=cols, mydata) %dopar% {
name <- names(mydata)[thiscol]
print(paste('transforming variable ', name))
mydata[,paste(name, 'sqrt', sep='_')] <<- sqrt(mydata[,thiscol])
mydata[,paste(name, 'log', sep='_')] <<- log(mydata[,thiscol])
}
}
n<-10 # I often have 100K-1M rows
mydata <- data.frame(
a=runif(n,1,100),
b=runif(n,1,100),
c=runif(n,1,100),
d=runif(n,1,100)
)
ncol(mydata) # 4 columns
transform_features()
ncol(mydata) # if it works, there should be 8
请注意,如果将%dopar%更改为%do%,则可以正常工作
答案 0 :(得分:2)
尝试data.table
中的:=
运算符,按引用添加列。您需要with=FALSE
,因此您可以将paste
的电话号码发送到:=
的LHS。
答案 1 :(得分:1)
如果你做了像
这样的事情,可能会更容易n<-10
mydata <- data.frame(
a=runif(n,1,100),
b=runif(n,1,100),
c=runif(n,1,100),
d=runif(n,1,100)
)
mydata_sqrt <- sqrt(mydata)
colnames(mydata_sqrt) <- paste(colnames(mydata), 'sqrt', sep='_')
mydata <- cbind(mydata, mydata_sqrt)
产生类似
的东西> mydata
a b c d a_sqrt b_sqrt c_sqrt d_sqrt
1 29.344088 47.232144 57.218271 58.11698 5.417018 6.872565 7.564276 7.623449
2 5.037735 12.282458 3.767464 40.50163 2.244490 3.504634 1.940996 6.364089
3 80.452595 76.756839 62.128892 43.84214 8.969537 8.761098 7.882188 6.621340
4 39.250277 11.488680 38.625132 23.52483 6.265004 3.389496 6.214912 4.850240
5 11.459075 8.126104 29.048527 76.17067 3.385126 2.850632 5.389669 8.727581
6 26.729365 50.140679 49.705432 57.69455 5.170045 7.081008 7.050208 7.595693
7 42.533937 7.481240 59.977556 11.80717 6.521805 2.735186 7.744518 3.436157
8 41.673752 89.043099 68.839051 96.15577 6.455521 9.436265 8.296930 9.805905
9 59.122106 74.308573 69.883037 61.85404 7.689090 8.620242 8.359607 7.864734
10 24.191878 94.059012 46.804937 89.07993 4.918524 9.698403 6.841413 9.438217
答案 2 :(得分:1)
有两种方法可以解决这个问题:
遍历每一列(或者,更好的是,列的一个子集)并应用转换来创建临时数据帧,返回该数据帧,然后执行数据框列表的cbind
,正如@Henry建议的那样。
循环转换,将每个转换应用于数据框,然后返回转换数据框cbind
,然后继续。
就个人而言,我倾向于这样做的方式是创建一个bigmatrix
对象(在内存中或在磁盘上,使用bigmemory
包),并且您可以访问所有列共享内存。只需预先分配您将填写的列,您就不需要进行事后cbind
。我倾向于在磁盘上这样做。请务必运行flush()
,以确保所有内容都写入磁盘。