以其他列为条件,在我的数据框中填充一列,并使用第三列中的值

时间:2019-03-27 14:29:57

标签: r dataframe conditional multiple-columns

警告:这个问题似乎很简单,以至于作为一个初学者,我可能无法在SO上较为复杂的主题中找到正确的解决方案(看起来hereherehere以及更多的地方)

我想基于另一列在数据框中填充一列,并使用其他列作为输入。 用一个例子更清楚:

  Version1 Version2 Version3 Version4 Presented_version Color
1     blue      red    green   yellow                 1    NA
2      red     blue   yellow    green                 4    NA
3   yellow    green      red     blue                 3    NA

我想用版本1 /版本2 /版本3 /版本4的值填充“ 颜色”列。 Presented_version 列告诉我这四个中的哪个值是必需的。 例如,在第1行中,Presented_version为1,因此所需的值在“ Version1”(“蓝色”)中。第1行的颜色应该是蓝色。

有人可以告诉我一种方法,而无需使用大量“ if”语句遍历数据框吗?

structure(list(Version1 = structure(1:3, .Label = c("blue", "red", 
"yellow"), class = "factor"), Version2 = structure(c(3L, 1L, 
2L), .Label = c("blue", "green", "red"), class = "factor"), Version3 = structure(c(1L, 
3L, 2L), .Label = c("green", "red", "yellow"), class = "factor"), 
    Version4 = structure(3:1, .Label = c("blue", "green", "yellow"
    ), class = "factor"), Presented_version = c(1L, 4L, 3L), 
    Color = c(NA, NA, NA)), class = "data.frame", row.names = c(NA, 
-3L))

======================= 编辑!

我简化了示例以解释我的问题,但是上面的示例与我的实际数据集在某些方面有所不同,因此解决方案做出了我的数据实际上不满足的假设。 这是data.frame的更准确表示。特别是,Presented_version与Version1 ... Version 4列的内容之间没有固定的匹配项(根据额外的列而有所不同,我现在称为Painter),Version1至Version4不一定在第1至4列中在我的数据集中。

  FillerColumn Painter Version1 Version2 Version3 Version4 Version_presented Color FillerColumn.1
1           77       A     blue      red    green   yellow                 1    NA             77
2           77       B      red     blue   yellow    green                 4    NA             77
3           77       C   yellow    green      red     blue                 3    NA             77
4           77       D      red     blue   yellow    green                 1    NA             77
structure(list(FillerColumn = c(77L, 77L, 77L, 77L), Painter = structure(1:4, .Label = c("A", 
"B", "C", "D"), class = "factor"), Version1 = structure(c(1L, 
2L, 3L, 2L), .Label = c("blue", "red", "yellow"), class = "factor"), 
    Version2 = structure(c(3L, 1L, 2L, 1L), .Label = c("blue", 
    "green", "red"), class = "factor"), Version3 = structure(c(1L, 
    3L, 2L, 3L), .Label = c("green", "red", "yellow"), class = "factor"), 
    Version4 = structure(c(3L, 2L, 1L, 2L), .Label = c("blue", 
    "green", "yellow"), class = "factor"), Version_presented = c(1L, 
    4L, 3L, 1L), Color = c(NA, NA, NA, NA), FillerColumn.1 = c(77L, 
    77L, 77L, 77L)), class = "data.frame", row.names = c(NA, 
-4L))

3 个答案:

答案 0 :(得分:4)

我们可以使用带有row/column索引的向量化选项来提取值,而不是进行任何循环

df1$color <- df1[1:4][cbind(1:nrow(df1), df1$Presented_version)]
df1$color
#[1] "blue"  "green" "red"  

基准

dfN <- df1[rep(seq_len(nrow(df1)), 1e6),]


system.time({
   dfN[1:4][cbind(1:nrow(dfN), dfN$Presented_version)]

 })
# user  system elapsed 
#   1.216   0.110   1.321


system.time({
 cols <- grep("^Version", names(dfN))
 unlist(mapply(function(x, y) dfN[x, cols][y], 
                    1:nrow(dfN),dfN$Presented_version))

 })
#  user  system elapsed 
# 319.907   1.644 322.418 

现在,让我们看看apply

的另一个选项
system.time({
  apply(dfN, 1, function(x) x[cols][as.numeric(x["Presented_version"])])
 }) 
#  user  system elapsed 
# 14.240   0.365  14.550 

答案 1 :(得分:2)

我喜欢弄乱数据集。尝试使用data.table melt方法

df <- setDT(df)

df1 <- melt.data.table(df,
                       id.vars = c('Presented_version'),
                       measure.vars = patterns('Version'),
                       value.name = 'Color',
                       variable.name = 'Version')[
  , version1 := str_extract(Version, '\\d+')][
    Presented_version == version1][
      version1 := NULL]

导致

   Presented_version  Version Color 
1:                 1 Version1  blue        
2:                 3 Version3   red        
3:                 4 Version4 green      

而且,如果您希望信息使用相同的原始结构

merge(df, 
      df1[, .(Presented_version, Color)],
      by = 'Presented_version')

   Presented_version Version1 Version2 Version3 Version4 Color
1:                 1     blue      red    green   yellow  blue
2:                 3   yellow    green      red     blue   red
3:                 4      red     blue   yellow    green green  

答案 2 :(得分:1)

使用mapply

的一种方法
cols <- grep("^Version", names(df))
df$Color <- unlist(mapply(function(x, y) df[x, cols][y], 
                   1:nrow(df),df$Presented_version))

df
#  Version1 Version2 Version3 Version4 Presented_version Color
#1     blue      red    green   yellow                 1  blue
#2      red     blue   yellow    green                 4 green
#3   yellow    green      red     blue                 3   red

使用apply

apply(df, 1, function(x) x[cols][as.numeric(x["Presented_version"])])
#[1] "blue"  "green" "red"