将键值对转换为数据框
Converting key value pair into a data frame
我现在有以下格式的键值数据
column1 column2 column3
length:30 width:20
length:20 height:10 width:10
现在我想将其转换为以下格式的数据框
Length width height
32 20
40 30 10
提前致谢
您可以使用 sub
删除文本
setNames(data.frame(lapply(dat, function(x) sub("[a-z]+:", "", x))),
c("length", "width"))
# length width
# 1 32 20
# 2 40 30
编辑
对于更新后的问题,
dat <- unlist(dat, use.names = F) # convert to list
keys <- unique(sub("([a-z]):.*", "\1", dat)) # extract the keys
keys <- keys[keys!=""] # remove empty strings like in your example
## Key-values in list
keyvals <- setNames(lapply(keys, function(x) {
as.numeric(sub("\D+", "", grep(x, dat, fixed=T, value=T)))
}), keys)
## Convert to data.frame
as.data.frame(do.call(cbind, lapply(keyvals, `length<-`, max(lengths(keyvals)))))
# length width height
# 1 30 20 10
# 2 20 10 NA
使用 dplyr/tidyr
的选项。我们用gather
将'wide'格式转换为'long',用filter
去掉空行(''
),用separate
创建两个变量('Val1' 和 'Val2')通过在 :
分隔符处分隔字符串,删除不需要的列 (select(-Var)
),按变量之一分组 ('Val1')创建一个序列列 ('indx'),然后从 'long' 转换回 'wide' 格式 (spread
).
library(dplyr)
library(tidyr)
gather(df1, Var, Val) %>%
filter(Val!='') %>%
separate(Val, c('Val1', 'Val2'), convert=TRUE) %>%
select(-Var) %>%
group_by(Val1) %>%
mutate(indx=row_number()) %>%
spread(Val1, Val2) %>%
select(-indx)
# height length width
#1 10 30 20
#2 NA 20 10
或使用 data.table
的类似方法。我们 unlist
初始数据集,并将其转换为具有单列 (setDT
) 的 'data.table'。使用 'data.table' 的开发版本中的 tstrsplit
,即 v1.9.5
,我们在 :
处拆分。基于分组变量 'V1' 创建序列列 ('indx'),删除 'NA' 行并使用 dcast
从 data.table
转换回 'long' 到 'wide' 格式。
library(data.table)#v1.9.5+
DT <- setDT(list(unlist(df1)))[, tstrsplit(V1, ':', type.convert=TRUE)
][, ind:=1:.N, V1][!is.na(V1)]
dcast(DT, ind~V1, value.var='V2')
# ind height length width
#1: 1 10 30 20
#2: 2 NA 20 10
数据
df1 <- structure(list(column1 = c("length:30", "length:20"),
column2 = c("width:20",
"height:10"), column3 = c("", "width:10")), .Names = c("column1",
"column2", "column3"), class = "data.frame", row.names = c(NA, -2L))
我现在有以下格式的键值数据
column1 column2 column3
length:30 width:20
length:20 height:10 width:10
现在我想将其转换为以下格式的数据框
Length width height
32 20
40 30 10
提前致谢
您可以使用 sub
setNames(data.frame(lapply(dat, function(x) sub("[a-z]+:", "", x))),
c("length", "width"))
# length width
# 1 32 20
# 2 40 30
编辑
对于更新后的问题,
dat <- unlist(dat, use.names = F) # convert to list
keys <- unique(sub("([a-z]):.*", "\1", dat)) # extract the keys
keys <- keys[keys!=""] # remove empty strings like in your example
## Key-values in list
keyvals <- setNames(lapply(keys, function(x) {
as.numeric(sub("\D+", "", grep(x, dat, fixed=T, value=T)))
}), keys)
## Convert to data.frame
as.data.frame(do.call(cbind, lapply(keyvals, `length<-`, max(lengths(keyvals)))))
# length width height
# 1 30 20 10
# 2 20 10 NA
使用 dplyr/tidyr
的选项。我们用gather
将'wide'格式转换为'long',用filter
去掉空行(''
),用separate
创建两个变量('Val1' 和 'Val2')通过在 :
分隔符处分隔字符串,删除不需要的列 (select(-Var)
),按变量之一分组 ('Val1')创建一个序列列 ('indx'),然后从 'long' 转换回 'wide' 格式 (spread
).
library(dplyr)
library(tidyr)
gather(df1, Var, Val) %>%
filter(Val!='') %>%
separate(Val, c('Val1', 'Val2'), convert=TRUE) %>%
select(-Var) %>%
group_by(Val1) %>%
mutate(indx=row_number()) %>%
spread(Val1, Val2) %>%
select(-indx)
# height length width
#1 10 30 20
#2 NA 20 10
或使用 data.table
的类似方法。我们 unlist
初始数据集,并将其转换为具有单列 (setDT
) 的 'data.table'。使用 'data.table' 的开发版本中的 tstrsplit
,即 v1.9.5
,我们在 :
处拆分。基于分组变量 'V1' 创建序列列 ('indx'),删除 'NA' 行并使用 dcast
从 data.table
转换回 'long' 到 'wide' 格式。
library(data.table)#v1.9.5+
DT <- setDT(list(unlist(df1)))[, tstrsplit(V1, ':', type.convert=TRUE)
][, ind:=1:.N, V1][!is.na(V1)]
dcast(DT, ind~V1, value.var='V2')
# ind height length width
#1: 1 10 30 20
#2: 2 NA 20 10
数据
df1 <- structure(list(column1 = c("length:30", "length:20"),
column2 = c("width:20",
"height:10"), column3 = c("", "width:10")), .Names = c("column1",
"column2", "column3"), class = "data.frame", row.names = c(NA, -2L))