我试图遍历数据框中的每个值,并根据该值从另一个数据框中提取信息。我有一些代码可用于执行嵌套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
循环,因为我一直在使用嵌套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文件生成的每个列表的迭代
答案 0 :(得分:1)
您的代码存在两个问题。一个是你应用函数正在错误的对象上运行,另一个是你无法通过sapply
现在sapply(ind_1, function(x) {pop.prob(df, ind_1)})
使用df和全部 ind_1
&#为pop.prob
做ind_1
的每个元素说&#34; 34;因此矩阵输出不正确。要在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
答案 1 :(得分:0)
这是一个矢量化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
版本更快。更不用说简洁了。
schedule: every mon,tue,wed,thu,fri 00:10