我试图遍历数据框中的每个值,并基于该值从另一个数据框中提取信息。我有一些代码可用于执行嵌套for循环,但我正在使用运行时间太长而无法实现的大型数据集。
为简化起见,我将提供最初只有一行的示例数据:
ind_1 <- data.frame("V01" = "pp", "V02" = "pq", "V03" = "pq")
ind_1
# V01 V02 V03
#1 pp pq pq
我也有这个数据框:
stratum <- rep(c("A", "A", "B", "B", "C", "C"), 3)
locus <- rep(c("V01", "V02", "V03"), each = 6)
allele <- rep(c("p", "q"), 9)
value <- rep(c(0.8, 0.2, 0.6, 0.4, 0.3, 0.7, 0.5, 0.5, 0.6), 2)
df <- as.data.frame(cbind(stratum, locus, allele, value))
head(df)
# stratum locus allele value
#1 A V01 p 0.8
#2 A V01 q 0.2
#3 B V01 p 0.6
#4 B V01 q 0.4
#5 C V01 p 0.3
#6 C V01 q 0.7
每个基因座有两个等位基因值,每个基因座的层也有三个值,因此每个基因座有六个不同的值。 ind_1
的列名对应于locus
中的df
列。对于ind_1
中的每个条目,我想返回一个值列表,这些值是根据df
(locus
中的列名)和数据条目(ind_1
或pp
)从pq
中的值列中提取的。对于ind_1
中的每个条目,列表中将有三个返回值,一个用于stratum
中的每个df
。
我尝试的代码如下:
library(dplyr)
library(magrittr)
pop.prob <- function(df, ind_1){
p <- df %>%
filter( locus == colnames(ind_1), allele == "p")
p <- as.numeric(as.character(p$value))
if( ind_1 == "pp") {
prob <- (2 * p * (1-p))
return(prob)
} else if ( ind_1 == "pq") {
prob <- (p^2)
return(prob)
}
}
test <- sapply(ind_1, function(x) {pop.prob(df, ind_1)} )
此代码提供的值包含不正确的值:
V01 V02 V03
[1,] 0.32 0.32 0.32
[2,] 0.32 0.32 0.32
[3,] 0.42 0.42 0.42
以及警告信息:
# 1: In if (ind_1 == "pp") { :
# the condition has length > 1 and only the first element will be used
理想情况下,我会得到以下输出:
> test
# $V01
# 0.32 0.48 0.42
#
# $V02
# 0.25 0.36 0.04
#
# $V03
# 0.16 0.49 0.25
我一直试图弄清楚如何在我的代码中不使用for
循环,因为我一直在使用嵌套的循环,这需要花费过多的时间。任何帮助确定如何为这个简化的数据集做这个将不胜感激。一旦我这样做,我可以将其应用于数据框,例如具有多行的ind_1
谢谢大家,如果示例数据不清楚,请告诉我
编辑
这是我的代码,适用于for
循环:
pop.prob.for <- function(df, ind_1){
prob.list <- list()
for( i in 1:length(ind_1)){
p <- df %>%
filter( locus == colnames(ind_1[i]), allele == "p")
p <- as.numeric(as.character(p$value))
if( ind_1[i] == "pp") {
prob <- (2 * p * (1-p))
} else if ( ind_1[i] == "pq") {
prob <- (p^2)
}
prob.list[[i]] <- prob
}
return(prob.list)
}
pop.prob.for(df, ind_1)
对于我的实际数据,我将添加一个额外的循环来遍历类似于ind_1
的数据框中的多个行,并保存作为.rdata文件生成的每个列表的迭代
您的代码有两个问题。一个是你的应用函数是在错误的对象上运行,另一个是你无法通过sapply
访问元素的名称
现在sapply(ind_1, function(x) {pop.prob(df, ind_1)})
说“对于ind_1
的每个元素使用df和所有的pop.prob
做ind_1
”,因此不正确的矩阵输出。要在ind_1
上按元素操作,你会写sapply(ind_1, function(x) {pop.prob(df, ind_1)})
此更改不起作用,因为您在函数中提取列名称,而"pp"
(第一个元素)没有列名称。要使用您编写的函数,您需要编写:
test <- sapply(1:dim(ind_1)[2], function(x) {pop.prob(df, ind_1[x])})
这样,您将以与for循环相同的方式进行迭代。还要注意你得到一个矩阵,因为sapply
试图将lapply
输出强制转换为向量或矩阵。如果你想要一个列表,只需使用lapply
这是一个矢量化的data.table
解决方案。应该比apply
或for
版本快得多。更不用说更简洁了。
library(data.table)
setDT(df)[, value := as.numeric(as.character(value))]
df[allele=='p',
.(prob = {if (ind_1[.GRP]=='pp') 2*value*(1-value) else value^2}),
by = locus]
# locus prob
# 1: V01 0.32
# 2: V01 0.48
# 3: V01 0.42
# 4: V02 0.25
# 5: V02 0.36
# 6: V02 0.04
# 7: V03 0.16
# 8: V03 0.49
# 9: V03 0.25