在R中:拆分字符向量以查找特定字符并返回数据框

时间:2018-03-20 13:30:34

标签: r dataframe vector split strsplit

我希望能够从数据框中的字符向量中提取特定字符并返回新的数据框。我想提取的信息是审计员对特定公司收入和资产负债表的评论。我的问题是审核员备注存储在包含不同备注的向量中。例如:

vec = c("A C G H D E")。由于"A" %in% vec不会返回TRUE,因此我必须使用strsplit来分解数据框中的每个字符向量,因此"A" %in% unlist(strsplit(dat[i, 2], " ")。这将返回TRUE

这是一个MWE:

dat <- data.frame(orgnr = c(1, 2, 3, 4), rat = as.character(c("A B C")))
dat$rat <- as.character(dat$rat)
dat[2, 2] <- as.character(c("A F H L H"))
dat[3, 2] <- as.character(c("H X L O"))
dat[4, 2] <- as.character(c("X Y Z A B C"))

现在,为了提取有关rat coloumn中每个字母的信息,我尝试了几种方法,遵循类似的问题,例如Roland对类似问题的回答(How to split a character vector into data frame?

DF <- data.frame(do.call(rbind, strsplit(dat$rat, " ", fixed = TRUE)))
DF
   X1 X2 X3 X4 X5 X6
1  A  B  C  A  B  C
2  A  F  H  L  H  A
3  H  X  L  O  H  X
4  X  Y  Z  A  B  C

返回以下错误消息:Warning message: In (function (..., deparse.level = 1) : number of columns of result is not a multiple of vector length (arg 2)

这是一个理想的方法,因为它很快,但我不能使用DF,因为它回收。 是否有办法插入NA而不是回收,因为向量的长度不同?

到目前为止,我已经通过结合使用for循环和ifelse语句找到了解决问题的方法。但是,用3轧机遮挡。这种方法需要数年时间!

dat$A <- 0

for(i in seq(1, nrow(dat), 1)) {
  print(i)
  dat[i, 3] <- ifelse("A" %in% unlist(strsplit(dat[i, 2], " ")), 1, 0)
}

dat$B <- 0

for(i in seq(1, nrow(dat), 1)) {
  print(i)
  dat[i, 4] <- ifelse("B" %in% unlist(strsplit(dat[i, 2], " ")), 1, 0)
}

这给出了我想要的结果:

dat
  orgnr         rat A B
1     1       A B C 1 1
2     2   A F H L H 1 0
3     3     H X L O 0 0
4     4 X Y Z A B C 1 1

我搜索了StackOverflow上可以找到的大部分相关问题。这个问题非常接近我的问题:How to convert a list consisting of vector of different lengths to a usable data frame in R?,但我不知道如何使用这种方法实现strsplit

2 个答案:

答案 0 :(得分:1)

我们可以使用grepl for循环来完成此任务。 + 0将列格式TRUEFALSE转换为1或0

for (col in c("A", "B")){
  dat[[col]] <- grepl(col, dat$rat) + 0
}
dat
#   orgnr         rat A B
# 1     1       A B C 1 1
# 2     2   A F H L H 1 0
# 3     3     H X L O 0 0
# 4     4 X Y Z A B C 1 1

如果性能问题,请尝试使用此data.table方法。

library(data.table)

# Convert to data.table
setDT(dat)

# Create a helper function
dummy_fun <- function(col, vec){
  grepl(col, vec) + 0
}

# Apply the function to A and B
dat[, c("A", "B") := lapply(c("A", "B"), dummy_fun, vec = rat)] 
dat
#    orgnr         rat A B
# 1:     1       A B C 1 1
# 2:     2   A F H L H 1 0
# 3:     3     H X L O 0 0
# 4:     4 X Y Z A B C 1 1

答案 1 :(得分:0)

使用Base R:

a=strsplit(dat$rat," ")
b=data.frame(x=rep(dat$orgnr,lengths(a)),y=unlist(a),z=1)
cbind(dat,as.data.frame.matrix(xtabs(z~x+y,b)))
  orgnr         rat A B C F H L O X Y Z
1     1       A B C 1 1 1 0 0 0 0 0 0 0
2     2   A F H L H 1 0 0 1 2 1 0 0 0 0
3     3     H X L O 0 0 0 0 1 1 1 1 0 0
4     4 X Y Z A B C 1 1 1 0 0 0 0 1 1 1

从这里你可以调用你想要的那些列:

d=as.data.frame.matrix(xtabs(z~x+y,b))
 cbind(dat,d[c("A","B")])
  orgnr         rat A B
1     1       A B C 1 1
2     2   A F H L H 1 0
3     3     H X L O 0 0
4     4 X Y Z A B C 1 1