我尝试将字符串向量拆分为data.frame对象,对于固定顺序,这不是问题(例如写成here),但在我的特定情况下,未来数据的列-frame在字符串对象中不完整。这就是玩具输入的输出结果:
input <- c("an=1;bn=3;cn=45",
"bn=3.5;cn=76",
"an=2;dn=5")
res <- do.something(input)
> res
an bn cn dn
[1,] 1 3 45 NA
[2,] NA 3.5 76 NA
[3,] 2 NA NA 5
我现在正在寻找能够以有效方式实现这一目标的函数do.something
。我现在的天真解决方案是循环输入对象strsplit
;
然后strsplit
再次=
然后填充data.frame
结果的结果。
有没有办法做更多R-like类似的?我担心按元素执行元素会花费很长时间来处理长向量input
。
编辑:为了完整起见,我天真的解决方案看起来像这样:
do.something <- function(x){
temp <- strsplit(x,";")
temp2 <- sapply(temp,strsplit,"=")
ul.temp2 <- unlist(temp2)
label <- sort(unique(ul.temp2[seq(1,length(ul.temp2),2)]))
res <- data.frame(matrix(NA, nrow = length(x), ncol = length(label)))
colnames(res) <- label
for(i in 1:length(temp)){
for(j in 1:length(label)){
curInfo <- unlist(temp2[[i]])
if(sum(is.element(curInfo,label[j]))>0){
res[i,j] <- curInfo[which(curInfo==label[j])+1]
}
}
}
res
}
EDIT2: 不幸的是,我的大输入数据看起来像这样(没有'='的条目):
input <- c("an=1;bn=3;cn=45",
"an;bn=3.5;cn=76",
"an=2;dn=5")
所以我无法比较我手头的问题给出的答案。我天真的解决方案是
do.something <- function(x){
temp <- strsplit(x,";")
tempNames <- sort(unique(sapply(strsplit(unlist(temp),"="),"[",1)))
res <- data.frame(matrix(NA, nrow = length(x), ncol = length(tempNames)))
colnames(res) <- tempNames
for(i in 1:length(temp)){
curSplit <- strsplit(unlist(temp[[i]]),"=")
curNames <- sapply(curSplit,"[",1)
curValues <- sapply(curSplit,"[",2)
for(j in 1:length(tempNames)){
if(is.element(colnames(res)[j],curNames)){
res[i,j] <- curValues[curNames==colnames(res)[j]]
}
}
}
res
}
答案 0 :(得分:4)
这是一种糟糕的技术,但有时候ept
(eval parse text
)很有用。
> library(plyr)
> rbind.fill(lapply(input, function(x) {l <- new.env(); eval(parse(text = x), envir=l); as.data.frame(as.list(l))}))
an cn bn dn
1 1 45 3.0 NA
2 NA 76 3.5 NA
3 2 NA NA 5
<强>更新强>
> z <- lapply(strsplit(input, ";"),
+ function(x) {
+ e <- Filter(function(y) length(y)==2, strsplit(x, "="))
+ r <- data.frame(lapply(e, `[`, 2))
+ names(r) <- lapply(e, `[`, 1)
+ r
+ })
> rbind.fill(z)
an bn cn dn
1 1 3 45 <NA>
2 <NA> 3.5 76 <NA>
3 2 <NA> <NA> 5
答案 1 :(得分:4)
这是另一种方法,即使您已编辑的数据也可以使用。使用regmatches
从输入向量中提取列名和值,然后运行与值匹配的每个列表元素到相应的列名。
# Get column names
tag <- regmatches( input , gregexpr( "[a-z]+" , input ) )
# Get numbers including floating point, replace missing values with NA
val <- regmatches( input , gregexpr( "\\d+\\.?\\d?|(?<=[a-z]);" , input , perl = TRUE ) )
val <- lapply( val , gsub , pattern = ";" , replacement = NA )
# Column names
nms <- unique( unlist(tag) )
# Intermeidate matrices
ll <- mapply( cbind , val , tag )
# Match to appropriate columns and coerce to data.frame
out <- data.frame( do.call( rbind , lapply( ll , function(x) x[ match( nms , x[,2] ) ] ) ) )
names(out) <- nms
# an bn cn dn
#1 1 3 45 <NA>
#2 <NA> 3.5 76 <NA>
#3 2 <NA> <NA> 5
答案 2 :(得分:2)
效率不高,并使用外部包。
rbind.fill
plyr
对其进行绑定
醇>
这是我的代码:
ll <- lapply(input,function(x){
xx <- unlist(strsplit(x,";"))
nn <- sub('([a-z]+)[=].*','\\1',xx)
vv <- sub('([a-z]+)[=]([0-9]+([.][0-9]+)?)','\\2',xx)
m <- t(data.frame(vv))
colnames(m) <- nn
as.data.frame(m)
})
library(plyr)
rbind.fill(ll)
rbind.fill(ll)
an bn cn dn
1 1 3 45 <NA>
2 <NA> 3.5 76 <NA>
3 2 <NA> <NA> 5
答案 3 :(得分:1)
rbind.fill
主题的另一个变体:
library(plyr)
mini.df <- function(x) {
y <- do.call(cbind,strsplit(x,"="))
z <- as.numeric(y[2,])
names(z) <- y[1,]
return(as.data.frame(t(z)))
}
res <- rbind.fill(lapply(strsplit(input,";"),mini.df))
这实际上与其他两种解决方案非常相似。我刚刚创建的数据帧略有不同。