在R数据框中将分隔符字符串拆分为不同的列

3
我可以帮助您翻译。需要将数据框中的字符串文字快速简洁地拆分成一组列。假设我有以下数据框:
data <- data.frame(id=c(1,2,3), tok1=c("a, b, c", "a, a, d", "b, d, e"), tok2=c("alpha|bravo", "alpha|charlie", "tango|tango|delta") )

请注意各列之间的分隔符不同。

通常情况下,字符串列的数量事先是未知的(尽管如果没有其他选择,我可以尝试发现所有可能的情况)。

我需要两个像这样的数据框:

tok1.occurrences:
    +----+---+---+---+---+---+
    | id | a | b | c | d | e | 
    +----+---+---+---+---+---+
    |  1 | 1 | 1 | 1 | 0 | 0 |
    |  2 | 2 | 0 | 0 | 1 | 0 |
    |  3 | 0 | 1 | 0 | 1 | 1 |
    +----+---+---+---+---+---+

tok2.occurrences:
    +----+-------+-------+---------+-------+-------+
    | id | alpha | bravo | charlie | delta | tango | 
    +----+-------+-------+---------+-------+-------+
    |  1 |   1   |   1   |    0    |   0   |   0   |
    |  2 |   1   |   0   |    1    |   0   |   0   |
    |  3 |   0   |   0   |    0    |   1   |   2   |
    +----+-------+-------+---------+-------+-------+

我尝试使用以下语法:

我尝试使用以下语法:

tok1.f = factor(data$tok1)
dummies <- model.matrix(~tok1.f)

这最终是一个不完整的解决方案。它能正确创建我的虚拟变量,但显然不能根据分隔符进行拆分。

我知道我可以使用“tm”包来找到文档-术语矩阵,但它似乎对于如此简单的标记化而言过于复杂了。有更直接的方法吗?


1
这里也有(我认为这是一个适合用作关闭原因的正确问题)。 - Simon O'Hanlon
实际上,我已经投票支持重新开放这个问题。虽然它们非常相似,但并不是完全重复的。然而,我建议您用自己尝试过的内容说明您的问题-即使没有其他好处,也能赢得人们的好感。目前,您没有编码错误/问题,只是希望别人为您解决一个任务。 - Simon O'Hanlon
我没有编码错误,因为我不知道该写哪些代码来完成任务。但是,实际上我使用了tm包进行了一些测试。基本上,我使用该包针对来自各个alpha、bravo、charlie、a、b等术语的词典构建了一个文档术语矩阵。 - Gabriele B
添加了第一次(不成功的)尝试。 - Gabriele B
3个回答

6
我能想到最简单的方法是使用我的cSplit函数dcast.data.table结合使用,像这样:
library(splitstackshape)
dcast.data.table(cSplit(data, "tok1", ", ", "long"), 
                 id ~ tok1, value.var = "tok1", 
                 fun.aggregate = length)
#    id a b c d e
# 1:  1 1 1 1 0 0
# 2:  2 2 0 0 1 0
# 3:  3 0 1 0 1 1

dcast.data.table(cSplit(data, "tok2", "|", "long"), 
                 id ~ tok2, value.var = "tok2", 
                 fun.aggregate = length)
#    id alpha bravo charlie delta tango
# 1:  1     1     1       0     0     0
# 2:  2     1     0       1     0     0
# 3:  3     0     0       0     1     2

编辑:更新了library(splitstackshape),因为cSplit现在是该包的一部分。


这太棒了,非常有效,而且运行得非常好,非常感谢! - Gabriele B

1
如果您不介意暂时使用 data.table,这可能适用于您:
library(data.table)

data <- data.frame(id=c(1,2,3), 
                   tok1=c("a, b, c", "a, a, d", "b, d, e"), 
                   tok2=c("alpha|bravo", "alpha|charlie", "tango|tango|delta"))

splitCols <- function(col_name, data) {

  # strsplit needs strings

  data[, col_name] <- as.character(data[, col_name])

  # make a list of single row data frames from the tabulation
  # of each of items from the split column

  tokens <- lapply(strsplit(data[, col_name], "[^[:alnum:]]+"), function(x) {
    tab <- table(x)
    setNames(rbind.data.frame(as.numeric(tab)), names(tab))
  })

  # use data.table's rbindlist, filling in missing values

  rbl <- rbindlist(tokens, fill=TRUE)

  # 0 out the NA's

  rbl[is.na(rbl)] <- 0

  # add the "id" column

  cbind(id=data$id, rbl)

}

lapply(names(data)[-1], splitCols, data)

## [[1]]
##    id a b c d e
## 1:  1 1 1 1 0 0
## 2:  2 2 0 0 1 0
## 3:  3 0 1 0 1 1
## 
## [[2]]
##    id alpha bravo charlie delta tango
## 1:  1     1     1       0     0     0
## 2:  2     1     0       1     0     0
## 3:  3     0     0       0     1     2

你最终会得到一个数据帧列表,然后可以根据需要进行处理。

这里“data.table”的优势在哪里?看起来大部分仍处于“data.frame”的操作级别... - A5C1D2H2I1M1N2O1R2T1
rbindlist完成填充部分。我尽量不再使用plyr,而是使用rbindlist来填补空缺。 - hrbrmstr

0
您可以使用以下方式使用stringr包:
require(stringr)

test_data <- data.frame(id=c(1,2,3), tok1=c("a, b, c", "a, a, d", "b, d, e"), tok2=c("alpha|bravo", "alpha|charlie", "tango|tango|delta") )

#conversion to character class and uniform delimeter as ","
test_data$tok1<-as.character(test_data$tok1)
test_data$tok1<-gsub(" ","",test_data$tok1)
test_data$tok2=gsub("\\|",",",as.character(test_data$tok2))

#Unique list of elements for each column
tok1.uniq=sort(unique(unlist(strsplit(as.character(test_data$tok1),","))))
tok2.uniq=sort(unique(unlist(strsplit(as.character(test_data$tok2),","))))

#Token count for each column

#In each row of token, find the count of characters using str_count from stringr package

第一列:

tok1.occurances=do.call(cbind,lapply(tok1.uniq,function(x) {

DF=data.frame(do.call(rbind,lapply(test_data$tok1,function(y,z=x) str_count(y,z))))
colnames(DF) = x
return(DF)

}
))

#Add ID number as column
tok1.occurances=data.frame(id=as.numeric(row.names(tok1.occurances)),tok1.occurances,stringsAsFactors=FALSE)


# > tok1.occurances
# id a b c d e
#  1 1 1 1 0 0
#  2 2 0 0 1 0
#  3 0 1 0 1 1

第二列:

tok2.occurances=do.call(cbind,lapply(tok2.uniq,function(x) {

DF=data.frame(do.call(rbind,lapply(test_data$tok2,function(y,z=x) str_count(y,z))))
colnames(DF) = x
return(DF)

}
))

tok2.occurances=data.frame(id=as.numeric(row.names(tok2.occurances)),tok2.occurances,stringsAsFactors=FALSE)


# > tok2.occurances
# id alpha bravo charlie delta tango
#  1     1     1       0     0     0
#  2     1     0       1     0     0
#  3     0     0       0     1     2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接