题
我有一个数据框,并为每个行中,据框我必须做一些复杂的查找和追加的某些数据文件。
该数据框含有的科学成果,对于选择井从96孔板,用于生物研究所以我想要做的事,如:
for (well in dataFrame) {
wellName <- well$name # string like "H1"
plateName <- well$plate # string like "plate67"
wellID <- getWellID(wellName, plateName)
cat(paste(wellID, well$value1, well$value2, sep=","), file=outputFile)
}
在我的程序的世界,我会做这样的:
for (row in dataFrame) {
#look up stuff using data from the row
#write stuff to the file
}
什么是"R方式"这样做?
解决方案
您可以试试这个,使用 apply()
功能
> d
name plate value1 value2
1 A P1 1 100
2 B P2 2 200
3 C P3 3 300
> f <- function(x, output) {
wellName <- x[1]
plateName <- x[2]
wellID <- 1
print(paste(wellID, x[3], x[4], sep=","))
cat(paste(wellID, x[3], x[4], sep=","), file= output, append = T, fill = T)
}
> apply(d, 1, f, output = 'outputfile')
其他提示
可以使用 by()
一>功能:
by(dataFrame, 1:nrow(dataFrame), function(row) dostuff)
但遍历行直接这样是很少你想要什么;你应该尝试而不是量化。请问您有什么在回路中的实际工作是在做什么?
首先,乔纳森的约矢量化点是正确的。如果您getWellID()函数被矢量,那么你可以跳过循环,只是用猫或write.csv:
write.csv(data.frame(wellid=getWellID(well$name, well$plate),
value1=well$value1, value2=well$value2), file=outputFile)
如果getWellID()不向量化,然后使用by
的乔纳森的建议或apply
的knguyen的建议应该工作。
否则,如果你真的想使用for
,你可以做这样的事情:
for(i in 1:nrow(dataFrame)) {
row <- dataFrame[i,]
# do stuff with row
}
您也可以尝试使用foreach
包,但它需要你熟悉这种语法。下面是一个简单的例子:
library(foreach)
d <- data.frame(x=1:10, y=rnorm(10))
s <- foreach(d=iter(d, by='row'), .combine=rbind) %dopar% d
一个最终选择是使用一个函数出plyr
包,在这种情况下,常规将是非常相似的应用的功能。
library(plyr)
ddply(dataFrame, .(x), function(x) { # do stuff })
我使用这个简单的效用函数:
rows = function(tab) lapply(
seq_len(nrow(tab)),
function(i) unclass(tab[i,,drop=F])
)
或者更快的,更少的明确形式:
rows = function(x) lapply(seq_len(nrow(x)), function(i) lapply(x,"[",i))
此功能只是分割一个data.frame到的行的列表。然后,你可以做一个正常的“表示”在此列表:
tab = data.frame(x = 1:3, y=2:4, z=3:5)
for (A in rows(tab)) {
print(A$x + A$y * A$z)
}
这问题您的代码将具有最小修改工作:
for (well in rows(dataFrame)) {
wellName <- well$name # string like "H1"
plateName <- well$plate # string like "plate67"
wellID <- getWellID(wellName, plateName)
cat(paste(wellID, well$value1, well$value2, sep=","), file=outputFile)
}
我认为与基础研发做到这一点最好的方法是:
for( i in rownames(df) )
print(df[i, "column1"])
在for( i in 1:nrow(df))
的方法的优点是,你不惹上麻烦,如果df
是空的,nrow(df)=0
。
我很好奇的非矢量化选项的时间性能。 为了这个目的,我已经使用函数f由knguyen定义
f <- function(x, output) {
wellName <- x[1]
plateName <- x[2]
wellID <- 1
print(paste(wellID, x[3], x[4], sep=","))
cat(paste(wellID, x[3], x[4], sep=","), file= output, append = T, fill = T)
}
和像在他的例子的数据帧:
n = 100; #number of rows for the data frame
d <- data.frame( name = LETTERS[ sample.int( 25, n, replace=T ) ],
plate = paste0( "P", 1:n ),
value1 = 1:n,
value2 = (1:n)*10 )
我包括两名矢量化功能(肯定比别人快),以猫()方法有write.table比较()一个...
library("ggplot2")
library( "microbenchmark" )
library( foreach )
library( iterators )
tm <- microbenchmark(S1 =
apply(d, 1, f, output = 'outputfile1'),
S2 =
for(i in 1:nrow(d)) {
row <- d[i,]
# do stuff with row
f(row, 'outputfile2')
},
S3 =
foreach(d1=iter(d, by='row'), .combine=rbind) %dopar% f(d1,"outputfile3"),
S4= {
print( paste(wellID=rep(1,n), d[,3], d[,4], sep=",") )
cat( paste(wellID=rep(1,n), d[,3], d[,4], sep=","), file= 'outputfile4', sep='\n',append=T, fill = F)
},
S5 = {
print( (paste(wellID=rep(1,n), d[,3], d[,4], sep=",")) )
write.table(data.frame(rep(1,n), d[,3], d[,4]), file='outputfile5', row.names=F, col.names=F, sep=",", append=T )
},
times=100L)
autoplot(tm)
将得到的图像显示了适用给出了一个非矢量化版本的最佳性能,而write.table()似乎优于猫()。
你可以使用 by_row
从功能的软件包 purrrlyr
为此:
myfn <- function(row) {
#row is a tibble with one row, and the same
#number of columns as the original df
#If you'd rather it be a list, you can use as.list(row)
}
purrrlyr::by_row(df, myfn)
默认情况下,返回的价值从 myfn
放入一个新的 清单列 在df叫 .out
.
如果这是唯一的输出你愿意,你可以写 purrrlyr::by_row(df, myfn)$.out
好吧,既然你问的R相当于其他语言中,我试图做到这一点。似乎工作虽然我还没有真正在看哪种技术中的R更有效。
> myDf <- head(iris)
> myDf
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
> nRowsDf <- nrow(myDf)
> for(i in 1:nRowsDf){
+ print(myDf[i,4])
+ }
[1] 0.2
[1] 0.2
[1] 0.2
[1] 0.2
[1] 0.2
[1] 0.4
虽然对于类别列,这将取你的数据帧,其你可以使用强制转换,如果需要as.character()。