从R中的字符串中提取字符并保存在不同的变量中

时间:2014-03-09 10:34:25

标签: string r split extract

我有以下数据集elections

var1 <- c("125677", "255422", "475544", "333344", "233452")
var2 <- c("PRB", "PAN", "PR", "PV", "PJ")
var3 <- c("PCB/PTdoB/PCO/PRB", "PAN", "DEM/PR/PT/PSDB/PMDB/PV", "DEM/PR/PT/PSDB/PMDB/PV/PSTU/PSOL", "DEM/PJ")
elections <- cbind(var1, var2, var3)

看起来像这样:

var1 var2 var3  
---------------    
125677 PRB PCB/PTdoB/PCO/PRB  
255422 PAN PAN  
475544 PR DEM/PR/PT/PSDB/PMDB/PV  
333344 PV DEM/PR/PT/PSDB/PMDB/PV/PSTU/PSOL 
233452 PJ DEM/PJ

我想将var3分解为另外八个变量,var4var11,这些变量可以由/var3分隔的字符填充。因此,我想要的结果是:

var1 var2 var3 var4 var5 var6 var7 var8 var9 var10 var11
---------------------------------------------------------    
125677 PRB PCB/PTdoB/PCO/PRB PCB PTdoB PCO PRB  
255422 PAN PAN PAN
475544 PR DEM/PR/PT/PSDB/PMDB/PV DEM PR PT PSDB PMDB PV
333344 PV DEM/PR/PT/PSDB/PMDB/PV/PSTU/PSOL DEM PR PT PSDB PMDB PV PSTU PSOL   
233452 PJ DEM/PJ DEM PJ

我能够使用strsplit(elections$var3, '/')得到一个接近我想要的结果,但问题是这会产生一个对象列表。因此,当var3中只有一个元素时,它会起作用,但当有多个元素时,它不起作用。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

直接的方法是在该变量上使用read.csv(或read.table)(在将其添加到现有数据集之前或之后)。在这里,我使用了read.csv,它默认带有fill = TRUE参数,可以按照您期望的方式拆分数据。

以下是一个例子:

read.csv(text = elections[, "var3"], sep = "/", header = FALSE)
#    V1    V2  V3   V4   V5 V6   V7   V8
# 1 PCB PTdoB PCO  PRB                  
# 2 PAN                                 
# 3 DEM    PR  PT PSDB PMDB PV          
# 4 DEM    PR  PT PSDB PMDB PV PSTU PSOL
# 5 DEM    PJ   

或者,可能(如果您的数据集是data.frame):

read.csv(text = as.character(elections$var3), sep = "/", header = FALSE)

这种方法基本上与我的“splitstackshape”包中的concat.split一起使用,虽然它会进行更多检查,并且可以方便地将输出组合回原始数据集。

假设现在“选举”是data.frame,用法将是:

library(splitstackshape)
concat.split(elections, "var3", "/", drop = TRUE)
#     var1 var2 var3_1 var3_2 var3_3 var3_4 var3_5 var3_6 var3_7 var3_8
# 1 125677  PRB    PCB  PTdoB    PCO    PRB                            
# 2 255422  PAN    PAN                                                 
# 3 475544   PR    DEM     PR     PT   PSDB   PMDB     PV              
# 4 333344   PV    DEM     PR     PT   PSDB   PMDB     PV   PSTU   PSOL
# 5 233452   PJ    DEM     PJ                                          

更新

但最终,read.csv有点慢(因此,通过扩展,concat.split方法会很慢)。我正在努力修改该功能的方法沿着以下几行,直到我提出更好的方法:

myMat <- function(inVec, sep) {
  if (!is.character(inVec)) inVec <- as.character(inVec)
  nCols <- max(vapply(gregexpr(sep, inVec, fixed = TRUE), length, 1L)) + 1
  M <- matrix("", ncol = nCols, nrow = length(inVec))
  Spl <- strsplit(inVec, sep, fixed = TRUE)
  Len <- vapply(Spl, length, 1L)
  Ind <- cbind(rep(seq_along(Len), Len), sequence(Len))
  M[Ind] <- unlist(Spl)
  M
}

一些基准

示例数据:

var1 <- c("125677", "255422", "475544", "333344", "233452")
var2 <- c("PRB", "PAN", "PR", "PV", "PJ")
var3 <- c("PCB/PTdoB/PCO/PRB", "PAN", "DEM/PR/PT/PSDB/PMDB/PV", "DEM/PR/PT/PSDB/PMDB/PV/PSTU/PSOL", "DEM/PJ")
elections <- data.frame(var1, var2, var3)

评估的功能:

fun1 <- function() myMat(elections$var3, "/")
fun2 <- function() read.csv(text = as.character(elections$var3), sep = "/", header = FALSE)

结果:

microbenchmark(fun1(), fun2())
# Unit: microseconds
#    expr     min        lq   median        uq      max neval
#  fun1() 159.936  175.5445  193.291  244.6075  566.188   100
#  fun2() 974.151 1017.1280 1070.796 1690.0100 2146.724   100

BIGGER数据(但仍然不是很大):

elections <- do.call(rbind, replicate(5000, elections, simplify = FALSE))
dim(elections)
# [1] 25000     3

microbenchmark(fun1(), fun2(), times = 10)
# Unit: milliseconds
#    expr       min        lq    median       uq       max neval
#  fun1()  195.1358  211.8841  232.1093  287.560  324.6918    10
#  fun2() 2764.8115 3524.7989 3626.1480 3639.303 3728.2099    10

我没有耐心等待一百万行fun2(),但对于fun1(),它需要大约19秒,这是好的,但不是我完全满意的。