我有以下数据集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
分解为另外八个变量,var4
到var11
,这些变量可以由/
中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
中只有一个元素时,它会起作用,但当有多个元素时,它不起作用。
有什么想法吗?
答案 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秒,这是好的,但不是我完全满意的。