【问题标题】:How to create a new column in R which matches multiple values from two different data frames如何在 R 中创建一个与来自两个不同数据帧的多个值匹配的新列
【发布时间】:2020-02-10 17:56:25
【问题描述】:

我有 2 个包含数千个变量的数据框。

一个有不同年龄的学生和评估他们的不同老师。所有老师都评估了多个不同的学生,但不是每个学生。

Teacher Student Age
0123    1       7
0145    1       7
0163    1       7
0175    2       8
0123    2       8
0194    2       8
0123    3       7 
0145    3       7

然后我有老师对不同年龄的特定刻板印象的评分。每位教师对每个年龄组的刻板印象进行评分。数据框如下所示。

Teacher Age 7   Age 8  Age 9
0123    1       1      1
0145    5       7      3
0163    4       7      1
0175    6       8      1
0183    3       8      1
0194    2       8      1
0120    3       7      4

我想在第一个数据框中创建一个新列,其中每行中的教师都匹配,并且值是他们的刻板印象响应,具体取决于每个学生的年龄。例如,在这个新列中,第一行中的值将是教师 123 对 7 岁儿童的刻板印象反应。在这种情况下,这是一个 1。

非常感谢您的帮助。我是 R 新手,我不知道从哪里开始。

编辑:我希望输出如下所示:

Teacher Student Age AgeStereotype
0123    1       7   1
0145    1       7   5
0163    1       7   4
0175    2       8   8
0123    2       8   1
0194    2       8   8
0123    3       7   1
0145    3       7   5

【问题讨论】:

  • 你能显示预期的输出吗
  • @akrun 我刚刚编辑它以显示所需的输出。

标签: r


【解决方案1】:
AS <- apply(DF1[,c("Teacher", "Age")], 1, function(x) {
    DF2[which(DF2$Teacher == x[1]), which(grepl(x[2], names(DF2)))]
    })
DF1["AgeStereotype"] <- AS

分别使用 DF1 和 DF2 您的第一个和第二个数据帧。

输出:

  Teacher Student Age AgeStereotype
1     123       1   7             1
2     145       1   7             5
3     163       1   7             4
4     175       2   8             8
5     123       2   8             1
6     194       2   8             8
7     123       3   7             1
8     145       3   7             5

【讨论】:

    【解决方案2】:

    您可以使用[ 即:

    transform(df1,AgeStereotype = `rownames<-`(df2,df2$Teacher)[cbind(Teacher,paste("Age",Age))])
    
      Teacher Student Age AgeStereotype
    1     123       1   7             1
    2     145       1   7             5
    3     163       1   7             4
    4     175       2   8             8
    5     123       2   8             1
    6     194       2   8             8
    7     123       3   7             1
    8     145       3   7             5
    

    【讨论】:

      【解决方案3】:

      最好通过将第二个数据框转换为 一个长数据框,然后将其加入您的第一个数据框。 在R 中有很多方法可以实现这一点,这是一种干净的方法 在tidyverse 中,特别是dplyr 和tidyr 函数。

      # Recreating your data
      df1 <- tibble::tribble(
        ~Teacher, ~Student, ~Age,
         "0123",    1,       7,
         "0145",    1,       7,
         "0163",    1,       7,
         "0175",    2,       8,
         "0123",    2,       8,
         "0194",    2,       8,
         "0123",    3,       7,
         "0145",    3,       7
        )
      
      df2 <- tibble::tribble(
        ~Teacher, ~Age.7, ~Age.8, ~Age.9,
           "0123",    1,       1,      1,
           "0145",    5,       7,      3,
           "0163",    4,       7,      1,
           "0175",    6,       8,      1,
           "0183",    3,       8,      1,
           "0194",    2,       8,      1,
           "0120",    3,       7,      4
        )
      
      # Load necessary libs
      library(dplyr, warn.conflicts = FALSE)
      library(tidyr)
      

      tidyr::pivot_longer() 将 df2 转换为长格式并 dplyr::mutate() 和 gsub() 和 as.numeric() 用于剃须 变量名的残基并转换为dbl.

      df2_long <-
        df2 %>%
        pivot_longer(Age.7:Age.9,
                     names_to = "Age",
                     values_to = "AgeStereotype") %>%
        mutate(Age = as.numeric(gsub("Age.", "", Age)))
      

      dplyr::left_join() 合并数据集,只保留那些教师, 在df1 中有一行。

      left_join(df1, df2_long)
      #> Joining, by = c("Teacher", "Age")
      #> # A tibble: 8 x 4
      #>   Teacher Student   Age AgeStereotype
      #>   <chr>     <dbl> <dbl>         <dbl>
      #> 1 0123          1     7             1
      #> 2 0145          1     7             5
      #> 3 0163          1     7             4
      #> 4 0175          2     8             8
      #> 5 0123          2     8             1
      #> 6 0194          2     8             8
      #> 7 0123          3     7             1
      #> 8 0145          3     7             5
      

      【讨论】:

        【解决方案4】:

        另一种base方式:

        merge(
          df1,
          data.frame(Teacher = df2$Teacher, 
                     Age = gsub("[[:alpha:]]", "", stack(df2[,-1])[,2]),
                     AgeStereotype = stack(df2[,-1])[,1]
          )
        )
        

        输出:

          Teacher Age Student AgeStereotype
        1     123   7       1             1
        2     123   7       3             1
        3     123   8       2             1
        4     145   7       1             5
        5     145   7       3             5
        6     163   7       1             4
        7     175   8       2             8
        8     194   8       2             8
        

        这确实改变了原始顺序,即使可以在没有额外包的情况下修改它,如果重要的话,也许最简单的方法就是让dplyr 进行连接:

        dplyr::left_join(
          df1,
          data.frame(Teacher = df2$Teacher, 
                     Age = as.integer(gsub("[[:alpha:]]", "", stack(df2[,-1])[,2])),
                     AgeStereotype = as.integer(stack(df2[,-1])[,1]), stringsAsFactors = FALSE
          )
        )
        

        【讨论】:

          猜你喜欢
          • 2019-07-15
          • 1970-01-01
          • 1970-01-01
          • 2022-01-11
          • 1970-01-01
          • 1970-01-01
          • 2018-03-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多