2016-02-27 78 views
1

我有一个表格(d.tab),其中包含问卷答案对。其中一些是单选答案,一些是多选题。我想从它的数值中查找单选答案的文本值。为此,我有一个查询表(d.lookup)。基于其他数据框映射替换某些行中的值

我尝试过merge这些,但它有点难看,因为我现在必须过滤掉value != answer_id的所有行。有没有更漂亮的方式做到这一点,可能使用plyrdplyrtidyr

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行做任何事情,但如果answer_id的比赛中value简单地更新原来的数据帧从d.tabanswer_text的实际文本,以取代value

我知道我可以做:

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

但是,这给了我一个新列answer_text与原value还在那里,我不需要。

+0

您可以通过合并多个列,即使可能有不同的名称。你真的只想合并单选答案是正确的吗?否则,具有'3,4'的行会有点棘手。 – Stibu

+0

是的,我不想对多选行做任何事情。这些仅仅是为了表明我只需要替换一部分值。 – slhck

+0

查看更新的问题;我只注意到我可以做这个多键合并,但它并没有完全达到我所需要的。 – slhck

回答

7

在您的问题中您有正确的电话merge()。剩下的就是你筛选单选答案的行并选择除value之外的所有列。

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) 

第二行包含因子变量value为数字的显式转换:使用dplyr,这可以如下完成。这很重要,因为将因素转换为数字可能会导致奇怪的结果。我会在下面添加一些关于这个主题的内容。

请注意dplyr还带有自己的函数来替换合并。如果你的桌子很大,你会注意到这些效率更高。使用left_joindplyr解读:

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 

所以,尽管merge()没有的因素,以数字的地方转换,我不会依赖于它做它以你想要的方式。因此,您应该明确地进行转换。

+0

这是一些很棒的建议,非常感谢!现在,我的问题略有变化。假设我有另外一个类型为'likert'的问题,并且查找表中只有answer_id和answer_text这两列(例如,答案1表示“强烈不同意”,2表示“不同意”等)。我将如何去取代我的原始数据框的值的子集(假设我保持原始列'值'完好无损)?当我在这里进行合并时,我得到了'answer_text.x'和'answer_text.y'列,前者对于我将替换它的行仍然是NA。 – slhck

+0

难道你只是通过'value'和'answer_id'进行合并。没有错,如果'd.tab'中有很多匹配。查找表中的匹配行将根据需要简单地合并到'd.tab'中。或者是你关于别的东西的问题? – Stibu

+1

是的,我可以做这个合并,但假设我已经做过其他合并之前,所以我已经有一个'answer_text'列,其中'question_type'是'likert'的行的NA值。如果我再做一次合并,我*已经*有一个'answer_text'列,然后在我的结果中得到'answer_text.x'和'answer_text.y'。如果没有数据 - 我可以理解 - 这有点难以成像 - 我可以发布一个新问题,当然是:) – slhck

2

data.table的替代解决方案:

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提到的,可能是更好的分割具有多个行值。从splitstackshapecSplit函数的一个例子:

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 
+0

看起来很干净,谢谢! (为什么还有一百万个解决方案来实现R中的一件事? – slhck

+0

这就像数学 - 许多方法可以得出相同的答案。 –

相关问题