繁体   English   中英

在R中分割字符串时,有效替换for循环

[英]Efficient replacement for for-loop when splitting strings in R

我有一个大型数据框(20列,> 100k行),需要将一列字符串拆分成多个新列。

有关列的前3个观察结果如下:

scans <- data.frame(scan = c("CT Cervical Sp,CT Head Plain", "II < 1 Hour", 
                 "L-S Spine,L-S Spine"))

看起来像这样:

                          scan
1 CT Cervical Sp,CT Head Plain
2                  II < 1 Hour
3          L-S Spine,L-S Spine

我需要将其拆分为5列(每个观察中最多有5个子串),对于具有较少子串的观察,我希望剩余的列填充有NA。 我目前正在使用此代码:

scans <- data.frame(scan = c("CT Cervical Sp,CT Head Plain", "II < 1 Hour",
"L-S Spine,L-S Spine"))

for(i in 1:nrow(scans)){
  scans$scan1[i] <- strsplit(scans$scan, ",")[[i]][1]
  scans$scan2[i] <- strsplit(scans$scan, ",")[[i]][2]
  scans$scan3[i] <- strsplit(scans$scan, ",")[[i]][3]
  scans$scan4[i] <- strsplit(scans$scan, ",")[[i]][4]
  scans$scan5[i] <- strsplit(scans$scan, ",")[[i]][5]
}

它工作并输出我想要的解决方案:

                          scan          scan1         scan2 scan3 scan4 scan5
1 CT Cervical Sp,CT Head Plain CT Cervical Sp CT Head Plain    NA    NA    NA
2                  II < 1 Hour    II < 1 Hour            NA    NA    NA    NA
3          L-S Spine,L-S Spine      L-S Spine     L-S Spine    NA    NA    NA

......但它确实很慢。 循环数十或数十万次观测是耗时的。

非常感谢任何建议。

另一种方法是使用tstrsplit开发人员版本data.table

library(data.table) # v >= 1.9.5
setDT(scans)[, tstrsplit(scan, ",", fixed = TRUE)]
#                V1            V2
# 1: CT Cervical Sp CT Head Plain
# 2:    II < 1 Hour            NA
# 3:      L-S Spine     L-S Spine 

如果您确定至少有5次拆分,则可以通过引用轻松创建这些列

setDT(scans)[, paste0("scan", 1:5) := tstrsplit(scan, ",")]

或者, tidyr包提供类似的functuanality

library(tidyr)
separate(scans, scan, paste0("scan", 1:2), ",", extra = "merge", remove = FALSE)
#                           scan          scan1         scan2
# 1 CT Cervical Sp,CT Head Plain CT Cervical Sp CT Head Plain
# 2                  II < 1 Hour    II < 1 Hour          <NA>
# 3          L-S Spine,L-S Spine      L-S Spine     L-S Spine

或者仅使用base R另一种选择

 cbind(scans, read.table(text= as.character(scans$scan),sep=",", fill=TRUE, na.strings=''))

您可以使用:

library(splitstackshape)
cSplit(scans, colnames(scans), sep=',')

#           scan_1        scan_2
#1: CT Cervical Sp CT Head Plain
#2:    II < 1 Hour            NA
#3:      L-S Spine     L-S Spine

请注意返回的对象是data.table 如果需要,您可以转换为data.frame 这里只有两列,因为数据中最多只有一个逗号。 如果将其应用于带有4个逗号的某些单元格的数据,您将获得所需的输出。

使用惊人的stringi包 - 我挑战任何人找到更快的解决方案。

# this does all the work
result <- as.data.frame(stringi::stri_split_fixed(scans$scan, ",", simplify = TRUE))

这将填充与逗号分隔符一样多的列。

要从问题中获得准确的结果,请重命名列并将空字符串转换为NA

# rename the columns if you wish
names(result) <- paste0("scan", 1:ncol(result))
# replace "" with NA
result[result==""] <- NA

cbind(scans, result)
##                           scan          scan1         scan2
## 1 CT Cervical Sp,CT Head Plain CT Cervical Sp CT Head Plain
## 2                  II < 1 Hour    II < 1 Hour          <NA>
## 3          L-S Spine,L-S Spine      L-S Spine     L-S Spine

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM