在 R 中使用 Vectors、现有变量和 mapply 创建多个新变量

Creating multiple new variables using Vectors, existing variables, and mapply in R

我是 R 的新手,我正在尝试在我的数据集中创建一个新的 columns/variables,df,使用来自我的数据集中已经存在的多个列的信息。我希望使用 mapply 函数来执行此操作。这是指在某人的右侧和左侧进行的某些测量的数据。然而,这些方面中只有一个受到影响,并且由 df$laterality 定义。最终,我想创建新的 variable/columns,它将从测量中收集的数据定义为从受影响的一侧收集的数据。

我的数据,经过简化,基本上如下所示

recordID <- c(1, 2, 3, 4)
laterality <- c(right, right, left, right)
right_1_measure <- c(2.3, 3.4, 1.7, 2.4)
right_2_measure <- c(1.3, 2.2, 3.1, 4.1)
right_3_measure <- c(2.7, 2.8, 4.2, 3.9)
left_1_measure <- c(1.5, 2.6, 4.5, 2.8)
left_2_measure <- c(1.1, 3.4, 3.5, 2.6)
left_3_measure <- c (2.6, 2.8, 3.6, 1.6)

df <- data.frame(recordID, laterality, right_1_measure, right_2_measure, right_3_measure, left_1_measure, left_2_measure, left_3_measure)

然后我创建了一个列名称的向量,我希望循环通过它来创建新的“受影响的”variable/columns,我将根据之前定义的变量命名,但添加前缀“aff” .我还创建了一个包含我希望赋予新列的名称的向量。

right_vars <- c("right_1_measure", "right_2_measure" , "right_3_measure")
left_vars <- c("left_1_measure", "left_2_measure" , "left_3_measure")
aff_vars <- c("aff_1_measure", "aff_2_measure", "aff_3_measure")

然后我创建了我计划用来根据 df$laterality

有条件地创建新列的函数
aff_var_create <- function (x, y, z){
  df$x <- ifelse(df$laterality == "Right" , df$y, ifelse (df$laterality == "Left", df$z, NA))
}

然后我创建了我的 mapply 代码

mapply(FUN = aff_var_create, x = aff_vars, y = r_vars, z = l_vars)

但是,当我 运行 这样做时,我收到以下错误消息:

Error in ans[ypos] <- rep(yes, length.out = len)[ypos] : 
  replacement has length zero
In addition: Warning message:
In rep(yes, length.out = len) :
 Error in ans[ypos] <- rep(yes, length.out = len)[ypos] : 
  replacement has length zero 

我检查了我的数据框,所有列中都有数据,所以我很困惑为什么 y.pos 的长度为零。

最终,我希望我的数据框如下所示

recordID <- c(1, 2, 3, 4)
laterality <- c(right, right, left, right)
right_1_measure <- c(2.3, 3.4, 1.7, 2.4)
right_2_measure <- c(1.3, 2.2, 3.1, 4.1)
right_3_measure <- c(2.7, 2.8, 4.2, 3.9)
left_1_measure <- c(1.5, 2.6, 4.5, 2.8)
left_2_measure <- c(1.1, 3.4, 3.5, 2.6)
left_3_measure <- c (2.6, 2.8, 3.6, 1.6)
aff_1_measure <- c(2.3, 3.4, 4.5, 2.4)
aff_2_measure <- c(1.3, 2.2, 3.5, 4.1)
aff_3_measure <- c(2.7, 2.8, 3.6, 3.9)

df <- data.frame(recordID, laterality, right_1_measure, right_2_measure, right_3_measure, left_1_measure, left_2_measure, left_3_measure, aff_1_measure, aff_2_measure, aff_3_measure)

如有任何解决此问题或使用其他方法获得类似结果的建议,我们将不胜感激!谢谢。

这不是 mapply 解决方案,但对于此类数据工作,我建议使用 tidyverse 包或至少其中的一部分:

library(dplyr)
library(tidyr)

df %>% 
  pivot_longer(matches("_\d+_measure"), names_to=c("side", "no"), names_pattern="(\w+)_(\d+)_measure") %>% 
  filter(laterality == side) %>% 
  select(-side) %>% 
  pivot_wider(names_from=no, names_glue="aff_{no}_measure") %>% 
  full_join(df, by=c("recordID", "laterality"))

哪个returns

# A tibble: 4 x 11
  recordID laterality aff_1_measure aff_2_measure aff_3_measure right_1_measure right_2_measure right_3_measure
     <dbl> <chr>              <dbl>         <dbl>         <dbl>           <dbl>           <dbl>           <dbl>
1        1 right                2.3           1.3           2.7             2.3             1.3             2.7
2        2 right                3.4           2.2           2.8             3.4             2.2             2.8
3        3 left                 4.5           3.5           3.6             1.7             3.1             4.2
4        4 right                2.4           4.1           3.9             2.4             4.1             3.9
# ... with 3 more variables: left_1_measure <dbl>, left_2_measure <dbl>, left_3_measure <dbl>

注意:您可以轻松更改列的顺序,使此输出与您想要的输出匹配。

我做了什么?

  • 首先,我们使用 pivot_longer 将数据转换为“长”格式。这使我们能够过滤数据以获得正确的偏侧性。
  • 现在我们必须采取措施使用 pivot_wider 创建 aff_n_measure 列。
  • 最后,我们使用 full_join.
  • 将这些新数据与您的旧数据结合起来

您不能使用 $ 表示法动态传递字符串值。而是使用 [[。此外,由于 mapply 不会就地更新数据框,您需要将结果分配给列:

right_vars <- c("right_1_measure", "right_2_measure" , "right_3_measure")
left_vars <- c("left_1_measure", "left_2_measure" , "left_3_measure")
aff_vars <- c("aff_1_measure", "aff_2_measure", "aff_3_measure")

aff_var_create <- function(x, y, z){
  ifelse(df$laterality == "right" , df[[y]], ifelse(df$laterality == "left", df[[z]], NA))
}

df[aff_vars] <- mapply(FUN=aff_var_create, x=aff_vars, y=right_vars, z=left_vars)

df

或者,通过使用 [ 的索引进行分配。

aff_cols <- paste0("aff_", 1:3, "_measure")
right_cols <- paste0("right_", 1:3, "_measure")
left_cols <- paste0("left_", 1:3, "_measure")
curr_logic <- df$laterality == "right"

# INITIALIZE COLUMNS
df[aff_cols] <- NA

# UPDATE COLUMNS BY INDEX
df[curr_logic , aff_cols] <- df[curr_logic , right_cols]
df[!curr_logic , aff_cols] <- df[!curr_logic, left_cols]

df

更好的是,使用单个 ifelse 调用,因为它可以 运行 向量和矩阵比较对齐到相同的维度(因此,replicate)。

aff_cols <- paste0("aff_", 1:3, "_measure")
right_cols <- paste0("right_", 1:3, "_measure")
left_cols <- paste0("left_", 1:3, "_measure")
curr_logic <- df$laterality == "right"

df[aff_cols] <- ifelse(replicate(3, curr_logic), 
                       as.matrix(df[right_cols]), 
                       as.matrix(df[left_cols]))

df