문제
데이터 프레임이 있고 해당 데이터 프레임의 각 행마다 복잡한 조회를 수행하고 파일에 데이터를 추가해야합니다.
데이터 프레임에는 생물학적 연구에 사용되는 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 way"는 무엇입니까?
해결책
당신은 이것을 사용하여 시도 할 수 있습니다 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)
그러나 이와 같이 직접 행을 반복하는 것은 당신이 원하는 것이 거의 없습니다. 대신 벡터화하려고 노력해야합니다. 루프의 실제 작업이 무엇을하고 있는지 물어볼 수 있습니까?
첫째, 벡터화에 대한 Jonathan의 요점은 정확합니다. getwellid () 함수가 벡터화되면 루프를 건너 뛰고 Cat 또는 Write.csv를 사용할 수 있습니다.
write.csv(data.frame(wellid=getWellID(well$name, well$plate),
value1=well$value1, value2=well$value2), file=outputFile)
getwellid ()가 벡터화되지 않으면 Jonathan의 사용 추천 by
또는 Knguyen의 제안 apply
작동해야합니다.
그렇지 않으면, 당신이 정말로 사용하고 싶다면 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))
이 기능은 데이터를 행 목록으로 나눕니다. 그런 다음이 목록 위에 "일반"을 만들 수 있습니다.
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)
}
기본 R 로이 작업을 수행하는 가장 좋은 방법은 다음과 같습니다.
for( i in rownames(df) )
print(df[i, "column1"])
에 대한 장점 for( i in 1:nrow(df))
-접근 방식은 당신이 곤경에 빠지지 않는다는 것입니다. df
비어 있고 nrow(df)=0
.
나는 벡터화되지 않은 옵션의 시간 성능에 대해 궁금했습니다. 이를 위해 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 )
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)
적용되는 결과 이미지는 벡터화되지 않은 버전에 대한 최상의 성능을 제공하는 반면 write.table ()는 Cat ()를 능가하는 것으로 보입니다.
당신은 사용할 수 있습니다 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. 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 ()를 사용하여 타이핑 할 수있는 데이터 프레임을 가져옵니다.