使用向量索引 R 中的 data.frame
Using a vector to index a data.frame in R
我有一个 data.frame,其中包含一个 ID 号和来自调查的按比例缩放的回复:
df(responses)
ID X1 X2 X3 X4
A1 1 1 2 1
B2 0 1 3 0
C3 3 3 2 0
我也有一个data.frame用作密钥:
df(key)
X Y Z
2 1 1
3 2 2
4 3 4
我正在尝试编写一个脚本来计算每个参与者的 X
、Y
和 Z
分数,其中 X
分数是总和对密钥中 X
下列出的问题的答复。
例如参与者 A1
的 X
分数将等于 X2
、X3
和 X4
在 A1
行 [=27] 中的总和=].
期望的输出是:
df(output)
ID X Y Z
A1 4 4 3
B2 4 4 1
C3 5 8 6
但是,我目前正在努力使用 key
中的值来索引 data.frame responses
。我目前的状态是:
#store scale names
scales <- c(colnames(key))
#loop over every participant
for (i in responses$ID){
#create temporary data.frame with only participant "i"s responses
data <- subset(responses, ID == i)
#loop over each scale and store the relevant response numbers
for (s in scales){
relevantResponses <- scales[c(s)]
#create a temporary storage for the total of each scale
runningScore <- 0
#index each response and add it to the total
for (r in relevantResponses){
runningScore <- runningScore + data[1,r]
但是我得到了错误:
Error in `[.data.frame`(data, 1, r) :
undefined columns selected
是否有比嵌套循环更好的索引方式?
我们可以使用rowSums
循环遍历key
数据列lapply
,根据索引提取'responses'数值列,得到rowSums
将 list
转换为 data.frame
和 cbind
以及 'responses'
的第一列
cbind(responses[1], data.frame(lapply(key,
function(x) rowSums(responses[-1][, na.omit(x)], na.rm = TRUE))))
-输出
# ID X Y Z
#1 A1 4 4 3
#2 B2 4 4 1
#3 C3 5 8 6
或 tidyverse
imap(key, ~ responses %>%
transmute(ID, !!.y := rowSums(select(cur_data()[-1], na.omit(.x)),
na.rm = TRUE))) %>%
reduce(inner_join)
-输出
# ID X Y Z
#1 A1 4 4 3
#2 B2 4 4 1
#3 C3 5 8 6
或者另一种选择是 mutate
和 across
key %>%
mutate(across(everything(),
~ rowSums(responses[-1][na.omit(.)], na.rm = TRUE)),
ID = responses$ID, .before = 1)
# ID X Y Z
#1 A1 4 4 3
#2 B2 4 4 1
#3 C3 5 8 6
数据
responses <- structure(list(ID = c("A1", "B2", "C3"), X1 = c(1L, 0L, 3L),
X2 = c(1L, 1L, 3L), X3 = c(2L, 3L, 2L), X4 = c(1L, 0L, 0L
)), class = "data.frame", row.names = c(NA, -3L))
key <- structure(list(X = 2:4, Y = 1:3, Z = c(1L, 2L, 4L)), class = "data.frame",
row.names = c(NA,
-3L))
这是处理此问题的另一种方法。我只是想用我最喜欢的解决方案来挑战自己,这并不像亲爱的@akrun 提出的那样简洁和出色。这是教我如何使用 purrr
函数族的人:
library(dplyr)
library(purrr)
responses %>%
select(X1:X4) %>%
pmap_dfr(., ~ map_dfc(1:length(key), function(x) sum(c(...)[key[, x]]))) %>%
bind_cols(responses$ID) %>%
set_names(c("x", "y", "z", "ID")) %>%
relocate(ID)
ID x y z
<chr> <int> <int> <int>
1 A1 4 4 3
2 B2 4 4 1
3 C3 5 8 6
我想在这里添加亲爱的@akrun 提出的两种更简洁的方法。一个具有 rowSums
功能,另一个具有 purrr
包中的 reduce
。请记住,当我们在数据框上应用带有 reduce 的 +
函数时,它将应用于每一行并将其折叠成一个元素:
map_dfc(key, ~ responses[-1][.x] %>% rowSums())
# A tibble: 3 x 3
X Y Z
<dbl> <dbl> <dbl>
1 4 4 3
2 4 4 1
3 5 8 6
与 reduce
:
map_dfc(key, ~ responses[-1][.x] %>% reduce(`+`))
# A tibble: 3 x 3
X Y Z
<int> <int> <int>
1 4 4 3
2 4 4 1
3 5 8 6
我有一个 data.frame,其中包含一个 ID 号和来自调查的按比例缩放的回复:
df(responses)
ID X1 X2 X3 X4
A1 1 1 2 1
B2 0 1 3 0
C3 3 3 2 0
我也有一个data.frame用作密钥:
df(key)
X Y Z
2 1 1
3 2 2
4 3 4
我正在尝试编写一个脚本来计算每个参与者的 X
、Y
和 Z
分数,其中 X
分数是总和对密钥中 X
下列出的问题的答复。
例如参与者 A1
的 X
分数将等于 X2
、X3
和 X4
在 A1
行 [=27] 中的总和=].
期望的输出是:
df(output)
ID X Y Z
A1 4 4 3
B2 4 4 1
C3 5 8 6
但是,我目前正在努力使用 key
中的值来索引 data.frame responses
。我目前的状态是:
#store scale names
scales <- c(colnames(key))
#loop over every participant
for (i in responses$ID){
#create temporary data.frame with only participant "i"s responses
data <- subset(responses, ID == i)
#loop over each scale and store the relevant response numbers
for (s in scales){
relevantResponses <- scales[c(s)]
#create a temporary storage for the total of each scale
runningScore <- 0
#index each response and add it to the total
for (r in relevantResponses){
runningScore <- runningScore + data[1,r]
但是我得到了错误:
Error in `[.data.frame`(data, 1, r) :
undefined columns selected
是否有比嵌套循环更好的索引方式?
我们可以使用rowSums
循环遍历key
数据列lapply
,根据索引提取'responses'数值列,得到rowSums
将 list
转换为 data.frame
和 cbind
以及 'responses'
cbind(responses[1], data.frame(lapply(key,
function(x) rowSums(responses[-1][, na.omit(x)], na.rm = TRUE))))
-输出
# ID X Y Z
#1 A1 4 4 3
#2 B2 4 4 1
#3 C3 5 8 6
或 tidyverse
imap(key, ~ responses %>%
transmute(ID, !!.y := rowSums(select(cur_data()[-1], na.omit(.x)),
na.rm = TRUE))) %>%
reduce(inner_join)
-输出
# ID X Y Z
#1 A1 4 4 3
#2 B2 4 4 1
#3 C3 5 8 6
或者另一种选择是 mutate
和 across
key %>%
mutate(across(everything(),
~ rowSums(responses[-1][na.omit(.)], na.rm = TRUE)),
ID = responses$ID, .before = 1)
# ID X Y Z
#1 A1 4 4 3
#2 B2 4 4 1
#3 C3 5 8 6
数据
responses <- structure(list(ID = c("A1", "B2", "C3"), X1 = c(1L, 0L, 3L),
X2 = c(1L, 1L, 3L), X3 = c(2L, 3L, 2L), X4 = c(1L, 0L, 0L
)), class = "data.frame", row.names = c(NA, -3L))
key <- structure(list(X = 2:4, Y = 1:3, Z = c(1L, 2L, 4L)), class = "data.frame",
row.names = c(NA,
-3L))
这是处理此问题的另一种方法。我只是想用我最喜欢的解决方案来挑战自己,这并不像亲爱的@akrun 提出的那样简洁和出色。这是教我如何使用 purrr
函数族的人:
library(dplyr)
library(purrr)
responses %>%
select(X1:X4) %>%
pmap_dfr(., ~ map_dfc(1:length(key), function(x) sum(c(...)[key[, x]]))) %>%
bind_cols(responses$ID) %>%
set_names(c("x", "y", "z", "ID")) %>%
relocate(ID)
ID x y z
<chr> <int> <int> <int>
1 A1 4 4 3
2 B2 4 4 1
3 C3 5 8 6
我想在这里添加亲爱的@akrun 提出的两种更简洁的方法。一个具有 rowSums
功能,另一个具有 purrr
包中的 reduce
。请记住,当我们在数据框上应用带有 reduce 的 +
函数时,它将应用于每一行并将其折叠成一个元素:
map_dfc(key, ~ responses[-1][.x] %>% rowSums())
# A tibble: 3 x 3
X Y Z
<dbl> <dbl> <dbl>
1 4 4 3
2 4 4 1
3 5 8 6
与 reduce
:
map_dfc(key, ~ responses[-1][.x] %>% reduce(`+`))
# A tibble: 3 x 3
X Y Z
<int> <int> <int>
1 4 4 3
2 4 4 1
3 5 8 6