【问题标题】:How to add column to a data.table in R that is based on a string in another column?如何将列添加到 R 中基于另一列中的字符串的 data.table?
【发布时间】:2014-02-12 09:08:51
【问题描述】:

我想根据另一列中的字符串向 data.table 添加列。这是我的数据和我尝试过的方法:

参数 1:{客户ID:459;时间:1386868908703;版本:6} 2:{客户ID:459;编号:52a9ea8b534b2b0b5000575f;时间:1386868824339;用户:459001} 3:{客户ID:988;时间:1388939739771} 4:{客户ID:459;编号:52a9ec00b73cbf0b210057e9;时间:1386868810519;用户:459001} 5:{客户ID:459;时间:1388090530634}

创建此表的代码:

DT = data.table(Params=c("{ clientID : 459;  time : 1386868908703;  version : 6}","{ clientID : 459;  id : 52a9ea8b534b2b0b5000575f;  time : 1386868824339;  user : 459001}","{ clientID : 988;  time : 1388939739771}","{ clientID : 459;  id : 52a9ec00b73cbf0b210057e9;  time : 1386868810519;  user : 459001}","{ clientID : 459;  time : 1388090530634}"))

我想解析“参数”列中的文本并根据其中的文本创建新列。例如,我希望有一个名为“user”的新列,它只包含 Params 字符串中“user:”之后的数字。添加的列应如下所示:

参数用户 1:{客户ID:459;时间:1386868908703;版本:6} 不适用 2:{客户ID:459;编号:52a9ea8b534b2b0b5000575f;时间:1386868824339;用户:459001} 459001 3:{客户ID:988;时间:1388939739771} 不适用 4:{客户ID:459;编号:52a9ec00b73cbf0b210057e9;时间:1386868810519;用户:459001} 459001 5:{客户ID:459;时间:1388090530634} 459001

我创建了以下函数来解析(在本例中为“用户”):

myparse <- function(searchterm, s) {
  s <-gsub("{","",s, fixed = TRUE)
  s <-gsub(" ","",s, fixed = TRUE)
  s <-gsub("}","",s, fixed = TRUE)
  s <-strsplit(s, '[;:]')
  s <-unlist(s)
  if (length(s[which(s==searchterm)])>0) {s[which(s==searchterm)+1]} else {NA}
}

然后我使用下面的函数来添加一列:

DT <- transform(DT, user = myparse("user", Params))

这适用于包含在所有行中的“时间”,但不适用于仅包含在两行中的“用户”。返回以下错误:

Error in data.table(list(Params = c("{ clientID : 459;  time : 1386868908703;  version : 6}",  : 
  argument 2 (nrow 2) cannot be recycled without remainder to match longest nrow (5)

我该如何解决这个问题?谢谢!

【问题讨论】:

    标签: regex r parsing transform data.table


    【解决方案1】:

    这里有一种使用正则表达式来完成这项任务的方法:

    myparse <- function(searchterm, s) {
      res <- rep(NA_character_, length(s)) # NA vector
      idx <- grepl(searchterm, s) # index for strings including the search term
      pattern <- paste0(".*", searchterm, " : ([^;}]+)[;}].*") # regex pattern
      res[idx] <- sub(pattern, "\\1", s[idx]) # extract target string
      return(res)
    }
    

    您可以使用此功能添加新列,例如user

    DT[, user := myparse("user", Params)]
    

    对于没有user 字段的行,新列包含NA

    DT[, user]
    # [1] NA       "459001" NA       "459001" NA
    

    【讨论】:

    • 非常感谢。适用于我提供的数据。我需要如何调整正则表达式以允许像“{ clientID : 461; time : 1386770861254; type : new; newUser : 461002}”这样的字符串,其中包括“type:new”之类的内容?
    • @Miriam 这个例子的结果应该是什么,"type:new""new"
    • 该列应命名为“type”,值应为“new”(如上面的 user:"459001")。
    • @Miriam Try DT[, type := myparse("type", Params)].
    • 由于某种原因,我不知道如果您将我们的 myparse 函数与我的字符串一起使用,这将不起作用:&gt; t &lt;- "{ clientID : 461; time : 1386770861254; type : new; newUser : 461002}" &gt; myparse("type", t) [1] "{ clientID : 461; time : 1386770861254; type : new; newUser : 461002}"与 myparse("time", t) 相比,返回整个字符串。知道可能是什么原因吗?
    【解决方案2】:

    我会使用一些外部解析器,例如:

    library(yaml)
    
    DT = data.frame(
        Params=c("{ clientID : 459;  time : 1386868908703;  version : 6}","{ clientID : 459;  id : 52a9ea8b534b2b0b5000575f;  time : 1386868824339;  user : 459001}","{ clientID : 988;  time : 1388939739771}","{ clientID : 459;  id : 52a9ec00b73cbf0b210057e9;  time : 1386868810519;  user : 459001}","{ clientID : 459;  time : 1388090530634}"), 
        stringsAsFactors=F
        )
    
    conv.to.yaml <- function(x){
         gsub(';  ','\n',substr(x, 3, nchar(x)-1))
    }
    
    tmp <- lapply( DT$Params, function(x) yaml.load(conv.to.yaml(x)) )  
    

    然后将解析后的列表组合成数据框:

    unames <- unique( unlist(sapply( tmp, names) ) )
    res <- as.data.frame(  do.call(rbind, lapply(tmp, function(x)x[unames]) ) )
    colnames( res ) <- unames
    res
    

    结果与您的想法非常接近,但您需要考虑更好地处理时间值:

    > res
      clientID       time version                       id   user
    1      459 -405527905       6                     NULL   NULL
    2      459 -405612269    NULL 52a9ea8b534b2b0b5000575f 459001
    3      988 1665303163    NULL                     NULL   NULL
    4      459 -405626089    NULL 52a9ec00b73cbf0b210057e9 459001
    5      459  816094026    NULL                     NULL   NULL
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-04
      • 2023-03-20
      • 2012-11-09
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多