【问题标题】:Creating multiple new variables using Vectors, existing variables, and mapply in R在 R 中使用向量、现有变量和 mapply 创建多个新变量
【发布时间】:2021-07-03 17:54:17
【问题描述】:

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

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

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)

然后,我创建了一个我希望循环通过的列名的向量,以创建新的“受影响”变量/列,我将根据先前定义的变量命名,但添加前缀“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)

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

【问题讨论】:

    标签: r dataframe mapply


    【解决方案1】:

    您不能使用$ 表示法动态传递字符串值。而是使用[[。另外,由于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
    

    【讨论】:

    • 很高兴听到并乐于提供帮助!请不要忘记 StackOverflow 的说法 thanks
    【解决方案2】:

    这不是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"))
    

    返回

    # 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 将这些新数据与您的旧数据结合起来。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多