代码之家  ›  专栏  ›  技术社区  ›  slhck

根据其他数据帧映射替换某些行中的值

  •  2
  • slhck  · 技术社区  · 10 年前

    我有一张桌子( d.tab )与调查中的问答配对。其中有些是单选答案,有些是选择题。我想从单选答案的数值中查找它的文本值。为此,我有一个查找表( d.lookup ).

    我试着 merge 这些,但有点难看,因为我现在必须过滤掉所有的行 value != answer_id 。有没有更漂亮的方法来做这件事,可能使用 plyr dplyr tidyr ?

    tab = '
    question_id question_type   subject value
    1   single-choice   1   1
    2   multiple-choice 1   2
    3   single-choice   1   2
    1   single-choice   2   2
    2   multiple-choice 2   3,4
    3   single-choice   2   2
    '
    
    lookup = '
    question_id answer_id   answer_text
    1   1   female
    1   2   male
    3   1   no
    3   2   yes
    '
    
    d.tab = read.table(text = tab, header = TRUE)
    d.lookup = read.table(text = lookup, header = TRUE)
    
    merge(d.tab, d.lookup, by = "question_id", all.x = TRUE)
    

    我什么都不想做 multiple-choice 行,但只需更新原始数据帧以替换 value 实际文本来自 d、 选项卡 answer_text 如果 answer_id s匹配 价值 .

    我知道我能做到:

    merge(d.tab, d.lookup, by.x = c("question_id", "value"), by.y = c("question_id", "answer_id"), all.x = TRUE)
    

    但这给了我一个新的专栏 答案_文本 与原件 价值 还在那里,我不需要。

    2 回复  |  直到 8 年前
        1
  •  8
  •   Stibu    10 年前

    您有正确的呼叫 merge() 在你的问题中。剩下的就是用单选答案筛选行,然后选择除 value 。使用dplyr,可以按如下方式完成:

    library(dplyr)
    filter(d.tab, question_type == "single-choice") %>%
      mutate(value = as.numeric(as.character(value))) %>%
      merge(d.lookup, by.x = c("question_id", "value"),
            by.y = c("question_id", "answer_id")) %>%
      select(-value)
    

    第二行包含因子变量的显式转换 价值 到数字。这很重要,因为将因子转换为数字可能会导致奇怪的结果。我将在下面添加几行关于这个主题的内容。

    请注意 dplyr 还附带了自己的功能来代替合并。如果你的桌子很大,你会发现这些更有效。使用 left_join 从…起 dplyr公司 解决方案如下:

    library(dplyr)
    filter(d.tab, question_type == "single-choice") %>%
      mutate(value = as.numeric(as.character(value))) %>%
      left_join(d.lookup,
                by = c("question_id" = "question_id",
                       "value" = "answer_id")) %>%
      select(-value)
    

    下面是关于我承诺的因素的评论。因子的问题是它们实际上是整数,其中每个整数值都有一个与其关联的标签。当你天真地用 as.numeric() ,您将获得与标签关联的整数。你的数据几乎肯定会遇到这个问题,这就是为什么。

    我创建了一个模拟您数据的因子变量:

    values <- factor(c("1", "2", "3,4", "3", "4"))
    

    现在我扔掉第三个值( "3,4" )并转换为数字:

    as.numeric(values[-3])
    ## [1] 1 2 3 5
    

    这可能不是你所期望的。原因是数字1到5与我们上面定义的五个级别相关联。如果要获得与标签匹配的数字,需要首先转换为字符:

    as.numeric(as.character(values[-3]))
    ## [1] 1 2 3 4
    

    所以,即使 合并() 在某处将因子转换为数字,我不会依赖于它以你想要的方式进行。因此,您应该显式地进行转换。

        2
  •  2
  •   Jaap    10 年前

    另一种解决方案 数据表 :

    library(data.table)
    
    # converting to datatables & setting the 'answer_id' to character
    setDT(d.tab)
    setDT(d.lookup)[, answer_id := as.character(answer_id)]
    
    # join 'd.tab' with 'd.lookup' and update 'value' by reference
    d.tab[d.lookup, value := answer_text, on = c("question_id", "value"="answer_id")]
    

    其给出:

       question_id   question_type subject  value
    1:           1   single-choice       1 female
    2:           2 multiple-choice       1      2
    3:           3   single-choice       1    yes
    4:           1   single-choice       2   male
    5:           2 multiple-choice       2    3,4
    6:           3   single-choice       2    yes
    

    正如@Stibu已经提到的,用多个值拆分行可能更好。一个示例 cSplit 函数 分叉叉 包裹:

    library(splitstackshape)
    cSplit(d.tab, "value", sep=",", 
           direction="long", 
           type.convert = FALSE)[d.lookup, 
                                 value := answer_text, 
                                 on = c("question_id", "value"="answer_id")]
    
    # or everything in 'data.table'
    d.tab[, lapply(.SD, function(x) unlist(tstrsplit(x, ','))), setdiff(names(d.tab),"value")
          ][d.lookup, value := answer_text, on = c("question_id", "value"="answer_id")][]
    

    两者都给出:

       question_id   question_type subject  value
    1:           1   single-choice       1 female
    2:           2 multiple-choice       1      2
    3:           3   single-choice       1    yes
    4:           1   single-choice       2   male
    5:           2 multiple-choice       2      3
    6:           2 multiple-choice       2      4
    7:           3   single-choice       2    yes
    
    推荐文章