编写函数以从 r 中的两个数据框中按变量名进行索引以查找值
writing function to index by variable name from two data frames in r to look up a value
我正在尝试编写一个函数来转换问卷的两个版本中的响应,根据响应将其编码为“是”或“否”。一些问题没有得到回答所以被编码为缺失
#example data
q1 <- c("column 2", "column 2", "column 1", NA, "column 1")
q2 <- c("column 1", "column 2", "column 2", NA, "column 1")
q3 <- c("column 1", "column 2", "column 1", "column 2", "column 1")
version <- c(1, 1, 2, 2, 1)
xdat <- data.frame(cbind(q1, q2, q3, version))
> xdat
q1 q2 q3 version
1 column 2 column 1 column 1 1
2 column 2 column 2 column 2 1
3 column 1 column 2 column 1 2
4 <NA> <NA> column 2 2
5 column 1 column 1 column 1 1
我创建了一个可能的响应数据框,其中包含每个版本的是或否响应的字符向量,以及每行的问题编号向量。
#make dataframe of values for converting the two versions of the questionnaire)
v1y <- c("column 2", "column 2", "column 1")
v1n <- c("column 1", "column 1", "column 2")
v2y <- c("column 1", "column 2", "column 1")
v2n <- c("column 2", "column 1", "column 2")
q <- c("q1", "q2", "q3")
#create reference dataframe, with character values
yn.dat <- data.frame(cbind(q, v1y, v1n, v2y, v2n), stringsAsFactors=FALSE)
> yn.dat
q v1y v1n v2y v2n
1 q1 column 2 column 1 column 1 column 2
2 q2 column 2 column 1 column 2 column 1
3 q3 column 1 column 2 column 1 column 2
然后我创建了一个函数来通过数据框中的问题变量查找版本和索引。
#function for calculating yes/no
yn.code <- function(v1y, v1n, v2y, v2n, q){
ifelse(xdat$version==1 & xdat[,q]==v1y, "yes", ifelse(xdat$version==2 & xdat[,q]==v2y, "yes", ifelse(xdat$version==1 & xdat[,q]==v1n, "no", ifelse(xdat$version==2 & xdat[,q]==v2n, "no", NA))))
}
当我 运行 函数时,它不会为所有响应生成正确的是和否值。
#result
yn.res <- yn.code(yn.dat$v1y, yn.dat$v1n, yn.dat$v2y, yn.dat$v2n, yn.dat$q)
> yn.res
q1 q2 q3
[1,] "yes" "yes" NA
[2,] NA "yes" "no"
[3,] "yes" NA "yes"
[4,] NA NA NA
[5,] NA "no" "yes"
它似乎在错误的地方为 NA 编码而且它没有return输入正确的值。
起初我认为函数循环遍历 yn.dat 中的 q 所以它读取第四行数据并将 q1 的规则应用于第四个受访者的所有响应,并将 q2 的规则应用于所有响应第五位受访者,但这似乎与问题所在不符。
可能我需要在函数中包含一个 %in% 参数来查找 yn.dat 中的 xdat 变量名称,然后 return 我正在寻找的值?
抱歉,如果这是一个简单的编程问题,但我已经为此绞尽脑汁了一段时间,而且还是个新手。
我不能告诉你为什么你的代码不能正常工作。但是如此复杂地使用 ifelse()
似乎不是一个好主意。
一种可能的替代方法是创建一个查找 table。为此,您的数据框 yn.dat
需要转换为不同的格式。根据您实际创建的方式 yn.dat
,从一开始就以该格式创建它可能更好,但我仍然可以向您展示如何从您当前的格式到达那里:
library(tidyr)
library(dplyr)
# convert to long format
yn.dat2 <- gather(yn.dat, type, answer, -q)
# split type up into version and yes/no
yn.dat2 <- mutate(yn.dat2, version = as.numeric(substr(type, 2, 2)),
yn = ifelse(substr(type, 3, 3) == "y", "yes", "no")) %>%
select(-type)
yn.dat2
## q answer version yn
## 1 q1 column 2 1 yes
## 2 q2 column 2 1 yes
## 3 q3 column 1 1 yes
## 4 q1 column 1 1 no
## 5 q2 column 1 1 no
## 6 q3 column 2 1 no
## 7 q1 column 1 2 yes
## 8 q2 column 2 2 yes
## 9 q3 column 1 2 yes
## 10 q1 column 2 2 no
## 11 q2 column 1 2 no
## 12 q3 column 2 2 no
问题(q
)、列(answer
)和version
的每种可能组合都有一行数据,对应的值为"yes"
或"no"
。现在,我将定义每行唯一特征的列名称,这将使我能够稍后查找 table:
row.names(yn.dat2) <- paste(yn.dat2$q, yn.dat2$answer, yn.dat2$version,
sep = "-")
接下来,我定义了一个函数,该函数使用查找 table 将 xdat
的单个列(以其名称为特征)转换为 "yes"
或 "no"
:
do_one_q <- function(q) {
keys <- paste(q, xdat[, q], xdat[, "version"], sep = "-")
yn.dat2[keys, "yn"]
}
我根据 xdat 中的值创建了我们用于上述行名称的相同类型的键。然后该键用于子集 yn.dat2
。并不是说这也适用于 "convert" xdat
中的 NA
s 到 NA
s:例如 q1
中的 NA
的键是 "q1-NA-2"
,如果您使用不存在的键进行索引,则返回 NA
:
yn.dat2["q1-NA-2", "yn"]
## [1] NA
因此不需要特殊处理缺失值。
最后一步是将此函数应用于所有问题,如下所示:
qs <- paste0("q", 1:3)
xdat_new <- as.data.frame(lapply(qs, do_one_q))
names(xdat_new) <- qs
xdat_new
## q1 q2 q3
## 1 yes no yes
## 2 yes yes no
## 3 yes yes yes
## 4 <NA> <NA> no
## 5 no no yes
编辑:
转换为长格式也可以使用 melt()
而不是 gather()
来完成。只需将涉及 gather()
的行替换为
library(reshape2)
# convert to long format
yn.dat2 <- melt(yn.dat, id = "q", variable.name = "type", value.name = "answer")
我正在尝试编写一个函数来转换问卷的两个版本中的响应,根据响应将其编码为“是”或“否”。一些问题没有得到回答所以被编码为缺失
#example data
q1 <- c("column 2", "column 2", "column 1", NA, "column 1")
q2 <- c("column 1", "column 2", "column 2", NA, "column 1")
q3 <- c("column 1", "column 2", "column 1", "column 2", "column 1")
version <- c(1, 1, 2, 2, 1)
xdat <- data.frame(cbind(q1, q2, q3, version))
> xdat
q1 q2 q3 version
1 column 2 column 1 column 1 1
2 column 2 column 2 column 2 1
3 column 1 column 2 column 1 2
4 <NA> <NA> column 2 2
5 column 1 column 1 column 1 1
我创建了一个可能的响应数据框,其中包含每个版本的是或否响应的字符向量,以及每行的问题编号向量。
#make dataframe of values for converting the two versions of the questionnaire)
v1y <- c("column 2", "column 2", "column 1")
v1n <- c("column 1", "column 1", "column 2")
v2y <- c("column 1", "column 2", "column 1")
v2n <- c("column 2", "column 1", "column 2")
q <- c("q1", "q2", "q3")
#create reference dataframe, with character values
yn.dat <- data.frame(cbind(q, v1y, v1n, v2y, v2n), stringsAsFactors=FALSE)
> yn.dat
q v1y v1n v2y v2n
1 q1 column 2 column 1 column 1 column 2
2 q2 column 2 column 1 column 2 column 1
3 q3 column 1 column 2 column 1 column 2
然后我创建了一个函数来通过数据框中的问题变量查找版本和索引。
#function for calculating yes/no
yn.code <- function(v1y, v1n, v2y, v2n, q){
ifelse(xdat$version==1 & xdat[,q]==v1y, "yes", ifelse(xdat$version==2 & xdat[,q]==v2y, "yes", ifelse(xdat$version==1 & xdat[,q]==v1n, "no", ifelse(xdat$version==2 & xdat[,q]==v2n, "no", NA))))
}
当我 运行 函数时,它不会为所有响应生成正确的是和否值。
#result
yn.res <- yn.code(yn.dat$v1y, yn.dat$v1n, yn.dat$v2y, yn.dat$v2n, yn.dat$q)
> yn.res
q1 q2 q3
[1,] "yes" "yes" NA
[2,] NA "yes" "no"
[3,] "yes" NA "yes"
[4,] NA NA NA
[5,] NA "no" "yes"
它似乎在错误的地方为 NA 编码而且它没有return输入正确的值。
起初我认为函数循环遍历 yn.dat 中的 q 所以它读取第四行数据并将 q1 的规则应用于第四个受访者的所有响应,并将 q2 的规则应用于所有响应第五位受访者,但这似乎与问题所在不符。
可能我需要在函数中包含一个 %in% 参数来查找 yn.dat 中的 xdat 变量名称,然后 return 我正在寻找的值?
抱歉,如果这是一个简单的编程问题,但我已经为此绞尽脑汁了一段时间,而且还是个新手。
我不能告诉你为什么你的代码不能正常工作。但是如此复杂地使用 ifelse()
似乎不是一个好主意。
一种可能的替代方法是创建一个查找 table。为此,您的数据框 yn.dat
需要转换为不同的格式。根据您实际创建的方式 yn.dat
,从一开始就以该格式创建它可能更好,但我仍然可以向您展示如何从您当前的格式到达那里:
library(tidyr)
library(dplyr)
# convert to long format
yn.dat2 <- gather(yn.dat, type, answer, -q)
# split type up into version and yes/no
yn.dat2 <- mutate(yn.dat2, version = as.numeric(substr(type, 2, 2)),
yn = ifelse(substr(type, 3, 3) == "y", "yes", "no")) %>%
select(-type)
yn.dat2
## q answer version yn
## 1 q1 column 2 1 yes
## 2 q2 column 2 1 yes
## 3 q3 column 1 1 yes
## 4 q1 column 1 1 no
## 5 q2 column 1 1 no
## 6 q3 column 2 1 no
## 7 q1 column 1 2 yes
## 8 q2 column 2 2 yes
## 9 q3 column 1 2 yes
## 10 q1 column 2 2 no
## 11 q2 column 1 2 no
## 12 q3 column 2 2 no
问题(q
)、列(answer
)和version
的每种可能组合都有一行数据,对应的值为"yes"
或"no"
。现在,我将定义每行唯一特征的列名称,这将使我能够稍后查找 table:
row.names(yn.dat2) <- paste(yn.dat2$q, yn.dat2$answer, yn.dat2$version,
sep = "-")
接下来,我定义了一个函数,该函数使用查找 table 将 xdat
的单个列(以其名称为特征)转换为 "yes"
或 "no"
:
do_one_q <- function(q) {
keys <- paste(q, xdat[, q], xdat[, "version"], sep = "-")
yn.dat2[keys, "yn"]
}
我根据 xdat 中的值创建了我们用于上述行名称的相同类型的键。然后该键用于子集 yn.dat2
。并不是说这也适用于 "convert" xdat
中的 NA
s 到 NA
s:例如 q1
中的 NA
的键是 "q1-NA-2"
,如果您使用不存在的键进行索引,则返回 NA
:
yn.dat2["q1-NA-2", "yn"]
## [1] NA
因此不需要特殊处理缺失值。
最后一步是将此函数应用于所有问题,如下所示:
qs <- paste0("q", 1:3)
xdat_new <- as.data.frame(lapply(qs, do_one_q))
names(xdat_new) <- qs
xdat_new
## q1 q2 q3
## 1 yes no yes
## 2 yes yes no
## 3 yes yes yes
## 4 <NA> <NA> no
## 5 no no yes
编辑:
转换为长格式也可以使用 melt()
而不是 gather()
来完成。只需将涉及 gather()
的行替换为
library(reshape2)
# convert to long format
yn.dat2 <- melt(yn.dat, id = "q", variable.name = "type", value.name = "answer")