【问题标题】:Creating dummy variables from substrings of factor levels从因子水平的子串创建虚拟变量
【发布时间】:2016-06-24 19:36:44
【问题描述】:

目标

使用包含 NA 或由空格分隔的一系列整数的因子变量,我试图创建一系列虚拟变量(var1、var2、...、vari),如果字符串包含整数,则其值为 1 i(不是简单的字符 i),如果字符串包含 NA,则为 NA,否则为 0。

问题

我有点卡住了,因为我尝试使用 grep() 在字符串中搜索定义每个整数的字符,但这会返回行号而不是布尔向量。此外,搜索“7”会返回“77”、“97”等,而不仅仅是“7”。

示例

因此,在下面的最小工作数据中,我希望虚拟变量 var0、var1、var2、var3、var33、var999 如果 data == NA 取值为 NA,如果 data == x 取值为 1,否则取值为 0。我已经放下了最初的尝试来解决这个不起作用的问题。由于我的实际数据非常大,我正在寻找一种通用的方法。

# Create data
data <- c("0 1 2", "0 2 3", "999", "33", "33 0 3", NA, "33 0 3") %>% factor()

# Attempt to complete task (doesn't work)
data <- cbind(data,
            setNames(
              data.frame(
                sapply(
                  data,
                  function(i) ifelse(is.na(data),
                                            NA,
                                            ifelse(# do something to create variables w/ value 1,0)))),
              paste0("var",
                    valuenumber))

在这种情况下,所需的输出类似于:

 data$var0
 [1] 1, 1, 0, 0, 1, NA, 1  # = 1 when string contains "0", NA when NA, 0 o/w

 data$var1
 [1] 1, 0, 0, 0, 0, NA, 0  # = 1 when string contains "1", NA when NA, 0 o/w

 data$var2
 [1] 1, 1, 0, 0, 0, NA, 0  # = 1 when string contains 2, NA when NA, 0 o/w

 # Important note: I want below to indicate when the string contains "3" and NOT "33"
 data$var3
 [1] 0, 1, 0, 0, 1, NA, 1  # = 1 when string contains 3, NA when NA, 0 o/w. 

 # Important note: I want below to indicate when the string contains "33" and NOT "3"
  data$var33
 [1] 0, 0, 0, 1, 1, NA, 1

  data$var999
 [1] 0, 0, 1, 0, 0, NA, 0

【问题讨论】:

  • 您可以粘贴所需的输出吗?在我看来,你所有的变量都会取值 1,因为所有 i 都在数据中?
  • 在上面提供了所需输出的示例。可能略有偏差,因为我需要手动输入值。另外提供了有关“33”和“3”的困难之一的cmets。

标签: r string


【解决方案1】:

您需要使用grepl,它返回TF,而不是grep,它返回匹配的值或匹配的位置,而且由于您使用的是字符串,因此最好以字符开头的因素,这里有一些关于如何做到这一点的开始。将变量名称重命名为 Vari 应该会给出所需的输出:

data <- c("0 1 2", "0 2 3", "999", "33", "33 0 3", NA, "33 0 3")

valueNumbers <- na.omit(unique(unlist(strsplit(data, " "))))
newData <- sapply(valueNumbers, function(i) replace(as.integer(
                  grepl(paste("\\b", i, "\\b", sep = ""), data)), is.na(data), NA))

newData

      0  1  2  3 999 33
[1,]  1  1  1  0   0  0
[2,]  1  0  1  1   0  0
[3,]  0  0  0  0   1  0
[4,]  0  0  0  0   0  1
[5,]  1  0  0  1   0  1
[6,] NA NA NA NA  NA NA
[7,]  1  0  0  1   0  1

要处理 cmets 中提到的 333 情况,您可以在 grepl 的模式中添加单词边界 \\b,这将区分 333

【讨论】:

    【解决方案2】:

    使用 strsplit 和匹配:

    # data
    data <- factor(c("0 1 2", "0 2 3", "999", "33", "33 0 3", NA, "33 0 3"))
    
    # make list
    dList <- sapply(as.character(data), strsplit, split = " ")
    # unique items
    items <- sort(unique(unlist(dList)))
    
    # result
    res <- data.frame(!is.na(t(sapply(dList, match, x = items)))) * 1
    colnames(res) <- paste0("var", items)
    
    # make no matches NA
    res[rowSums(res) == 0,] <- NA
    
    
    cbind(data, res)
    #       data var0 var1 var2 var3 var33 var999
    # 1    0 1 2    1    1    1    0     0      0
    # 2    0 2 3    1    0    1    1     0      0
    # 3      999    0    0    0    0     0      1
    # 4       33    0    0    0    0     1      0
    # 5   33 0 3    1    0    0    1     1      0
    # 6     <NA>   NA   NA   NA   NA    NA     NA
    # 7   33 0 3    1    0    0    1     1      0
    

    【讨论】:

    • @user3614648 为什么不呢?使用提供的示例数据,此代码有效。你的意思是因为它是因素吗?查看我的编辑。
    • 您已编辑,现在可以使用 - 需要转换为角色。
    • 很好用strsplit。加一个
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 2017-03-25
    • 1970-01-01
    • 2013-10-08
    • 2017-05-23
    相关资源
    最近更新 更多