【问题标题】:Extract characters from string in R and save in different variables从R中的字符串中提取字符并保存在不同的变量中
【发布时间】:2014-03-09 10:34:24
【问题描述】:

我有以下数据集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 中只有一个元素时它可以工作,但当有多个元素时它不会。

有什么想法吗?

【问题讨论】:

  • 您的代码显示matrix,但您尝试的解决方案显示了一种可用于data.frame 的方法。您的“选举”数据集的实际形式是什么?
  • 这是一个data.frame

标签: string r split extract


【解决方案1】:

直接的方法是对该变量使用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

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

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 秒,这还可以,但我并不完全满意。

【讨论】:

  • 当使用read.xxx 方法时,也许值得指出fill = TRUE 参数是一个线索。在read.csv 中默认为TRUE,但在read.table 中需要将默认FALSE 更改为TRUE。 +1!
  • concat.split 正是我想要的。非常感谢你,阿难。也感谢您指出这一点,Henrik。
  • 函数concat.split 现已弃用。请改用cSplit
猜你喜欢
  • 2020-12-31
  • 1970-01-01
  • 1970-01-01
  • 2016-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多