给定另一个变量的值重新编码一个变量的值

Recode the value of a variable given the value of another one

我使用的数据集在给定国家/地区的答案编码方式上存在错误。让我们调用我的第一个变量 my.data$country_year 和第二个变量 my.data$attitude。两者中的 table 给出以下输出:

table(my.data$country_year, my.data$attitude)

       (1) Very Suitable (2) Suitable (3) Somewhat Suitable (4) Not Suitable                      
Yemen.2006    101            142             1192                       0
Lebanon.2007   13           14                    60                  1063
Yemen.2007       49          113                   122                  248
Palestine.2008    131          653                   387                2093

有问题的 table 有很多我在这个 example.What 中省略的国家 我想做的是让 R 在我的原始数据集中执行以下操作,同时保留所有的观察结果其他国家:

for my.data$country="Yemen.2006" & my.data$attitude="(3) 有点随table", "(4) 不随table.

for my.data$country="Yemen.2006" & my.data$attitude="(2) Suitable", "(3) Something Suitable

换句话说,我想将 2006 年在也门进行的调查的态度变量的第二个和第三个值向右移动,而不创建新变量。我希望结果如下

 (1) Very Suitable (2) Suitable (3) Somewhat Suitable (4) Not Suitable                      
Yemen.2006    101            0                   142                 1192                       
Lebanon.2007   13            14                    60                  1063
Yemen.2007       49          113                   122                  248
Palestine.2008    131          653                   387                2093

我假设态度是一个因素。在那种情况下,我们可以做

levels(my.data$attitude) <- levels(my.data$attitude)[c(1, 4, 2, 3)]

如果它还不是一个因素,那就让它成为一个因素(至少暂时):

my.data$attitude <- factor(my.data$attitude)
levels(my.data$attitude) <- levels(my.data$attitude)[c(1, 4, 2, 3)]
my.data$attitude <- as.character(my.data$attitude)

仅更新​​ Yemen.2006 同样,假设态度是一个因素:

new_value_index <- c(1, 4, 2, 3)
my.data <- within(my.data, {
  attitude[country == "Yemen.2006"] <- levels(attitude)[new_value_index[attitude[country == "Yemen.2006]]] )
})

好的,谢谢大家,我根据你们的回答来寻找解决方案。我用较少的变量创建了 my.data 的一个子集,这次 within 函数工作正常。只有r2evans的脚本效果最好,如下

my.data2 <- within(my.data2, {attitude[country_year=="Yemen.2006" & 
attitude=="(3) Somewhat Suitable"] <- "(4) Not Suitable At All" })

my.data2 <- within(my.data2, {attitude[country_year=="Yemen.2006" & 
attitude=="(2) Suitable"] <- "(3) Somewhat Suitable" })

干杯,感谢您的时间和帮助!

OP 提到

The table in question has a lot of countries which I omitted in this example.

如果 table 很大并且只有几行要更新,我建议使用 data.table,它仅通过引用 更新受影响的行 无需复制整个数据对象。

有两种方法:一种是 select 和替换,另一种是使用 update join 和查找table.

Select 并替换

这类似于 但在 data.table 语法中:

library(data.table)
setDT(my.data)[country_year == "Yemen.2006" & attitude == "(3) Somewhat Suitable", 
        attitude := "(4) Not Suitable"]
my.data[country_year == "Yemen.2006" & attitude == "(2) Suitable", 
        attitude := "(3) Somewhat Suitable"]

注意my.data被修改就地,所以没有必要将结果分配给另一个数据帧。结果可以通过

dcast(my.data, country_year ~ attitude)

table(my.data$country_year, my.data$attitude)
                 (1) Very Suitable (2) Suitable (3) Somewhat Suitable (4) Not Suitable
  Yemen.2006                   101            0                   142             1192
  Lebanon.2007                  13           14                    60             1063
  Yemen.2007                    49          113                   122              248
  Palestine.2008               131          653                   387             2093

更新加入

这里,预先创建了一个 lookup table,然后在连接中使用它来仅更新 my.data 的匹配行:

library(data.table)
lookup <- data.table(
  country_year = "Yemen.2006", 
  attitude.old = c("(2) Suitable", "(3) Somewhat Suitable"),
  attitude.new = c("(3) Somewhat Suitable", "(4) Not Suitable"))
setDT(my.data)[lookup, on = .(country_year, attitude == attitude.old), 
  attitude := attitude.new][]

结果同上

可重现的数据

为了测试上述解决方案,我根据 table(...) 的给定输出重构了 my.data。请注意,my.data 是长格式,需要 melt() 样本 table 并根据计数给定的次数复制行:

DT_wide <- fread(
  "country_year, (1) Very Suitable, (2) Suitable, (3) Somewhat Suitable, (4) Not Suitable
Yemen.2006,    101,            142,             1192,                       0
  Lebanon.2007,   13,           14 ,                   60,                  1063
  Yemen.2007   ,    49,          113,                   122,                  248
  Palestine.2008,    131,          653,                   387,                2093")
DT_wide[, country_year := forcats::fct_inorder(country_year)]
my.data <- melt(DT_wide, id = "country_year", variable.name = "attitude")[
  rep(1:.N, value)][, value := NULL][]

my.data
        country_year          attitude
   1:     Yemen.2006 (1) Very Suitable
   2:     Yemen.2006 (1) Very Suitable
   3:     Yemen.2006 (1) Very Suitable
   4:     Yemen.2006 (1) Very Suitable
   5:     Yemen.2006 (1) Very Suitable
  ---                                 
6377: Palestine.2008  (4) Not Suitable
6378: Palestine.2008  (4) Not Suitable
6379: Palestine.2008  (4) Not Suitable
6380: Palestine.2008  (4) Not Suitable
6381: Palestine.2008  (4) Not Suitable