对于R数据框中的每一行

我有一个数据框,并为该数据框中的每一行,我不得不做一些复杂的查找,并追加到一个文件的一些数据。

dataFrame包含了来自生物学研究中使用的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) 

但是像这样直接遍历行很less是你想要的; 你应该尝试vector化。 我可以问一下循环中的实际工作是做什么的?

首先,乔纳森关于vector化的观点是正确的。 如果你的getWellID()函数是vector化的,那么你可以跳过循环,只使用cat或write.csv:

 write.csv(data.frame(wellid=getWellID(well$name, well$plate), value1=well$value1, value2=well$value2), file=outputFile) 

如果getWellID()不是向量化的,那么Jonathanbuild议使用或knguyen的applybuild议应该工作。

否则,如果你真的想用,你可以做这样的事情:

 for(i in 1:nrow(dataFrame)) { row <- dataFrame[i,] # do stuff with row } 

你也可以尝试使用foreach包,尽pipe它需要你熟悉这个语法。 这是一个简单的例子:

 library(foreach) d <- data.frame(x=1:10, y=rnorm(10)) s <- foreach(d=iter(d, by='row'), .combine=rbind) %dopar% d 

最后的select是使用plyr包中的函数,在这种情况下,约定与apply函数非常相似。

 library(plyr) ddply(dataFrame, .(x), function(x) { # do stuff }) 

我使用这个简单的实用function:

 rows = function(tab) lapply( seq_len(nrow(tab)), function(i) unclass(tab[i,,drop=F]) ) 

或者更快,更不明确的forms:

 rows = function(x) lapply(seq_len(nrow(x)), function(i) lapply(x,"[",i)) 

这个函数只是将一个data.frame分割成一个行列表。 那么你可以在这个列表中做一个正常的“for”:

 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) } 

我很好奇非vector化选项的时间performance。 为此,我使用了由knguyen定义的函数f

 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 ) 

我包括两个向量化函数(肯定比其他人快),以便比较cat()方法和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) 

由此产生的图像显示,应用程序提供了一个非vector化版本的最佳性能,而write.table()似乎优于猫()。 ForEachRunningTime

那么,既然你问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()进行types转换。

您可以使用包purrrlyrby_row函数来执行此操作:

 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来做这件事最好的方法是:

 for( i in rownames(df) ) print(df[i, "column1"]) 

比(我在1:nrow(df))方法中的优点是,如果df为空且nrow(df)= 0,则不会遇到麻烦。