优雅的方法将1-many列解析为R中的新data.frame

时间:2013-08-01 01:44:54

标签: r reshape

我从excel电子表格中读取了一些数据,其中策展人不了解关系数据库并处理1-many关系,因此将多个变量放在一列中:

>df <- data.frame(id=c("X1", "X23", "X5"), vars=c("foo, bar, hello", "world", NA), var2=c(1,2,3))
>df
   id            vars var2
1  X1 foo, bar, hello    1
2 X23           world    2
3  X5            <NA>    3

我想将vars列转换为新数据框,以便我可以拥有1-many关系:

>df
     id var2
X1   X1    1
X23 X23    2
X5   X5    3

>df2
   id   var
1  X1   foo
2  X1   bar
3  X1 hello
4 X23 world

我能够将vars列解析为一个列表,其中每个条目都是变量的向量:

>library(stringr)
>halfway <- str_split(df$vars, pattern=", ")
>halfway
[[1]]
[1] "foo"   "bar"   "hello"

[[2]]
[1] "world"

[[3]]
[1] NA

但我不确定如何获取此列表并将其转换为较长的data.frame

我有一个游戏,但我不能把它变成长格式而不会丢失每个变量所属的ID的信息(使用unlist)。 我也看了reshape,但它似乎没有做我想要的。

我可以使用for循环来迭代地构建新表,但这非常低效。对此有优雅的解决方案吗?

3 个答案:

答案 0 :(得分:2)

这可以通过data.table包以非常简单的方式完成:

library(data.table)
dt = as.data.table(df)
df2 = dt[, list(var=str_split(vars, ", ")[[1]]), by=id]
df2 = df2[!is.na(var), ]

这样做的一个优点是,如果您有多个ID列(例如,id,id2,id3),您可以将其更改为

df2 = dt[, list(var=strsplit(vars, ", ")[[1]]), by=c("id", "id2", "id3")]

答案 1 :(得分:2)

来自我的“splitstackshape”包的

concat.split.multiple有一个选项来执行拆分并一步完成整形,只剩下删除NA值的行:

library(splitstackshape)
out <- concat.split.multiple(df, "vars", ",", direction = "long")
out[complete.cases(out), ]
#    id var2 time  vars
# 1  X1    1    1   foo
# 2 X23    2    1 world
# 4  X1    1    2   bar
# 7  X1    1    3 hello

other scenarios has fared quite well函数{{3}}关于速度的“胆量”。我从未对此特定功能进行基准测试(主要是因为我从未真正处理过非常大的数据集)。

答案 2 :(得分:1)

expand.grid函数通常可用于重塑数据。例如:

> expand.grid(df[1,1],halfway[[1]])
  Var1  Var2
1   X1   foo
2   X1   bar
3   X1 hello

您可以使用apply对数据框的每一行执行此操作:

threequarterway <- lapply(seq(nrow(df)),function(i) expand.grid(df[i,1],halfway[[i]]))

do.call将结果列表元素绑定到单个数据框中:

df2 <- do.call(rbind,threequarterway)

最后,像David Robinson的回答一样摆脱NA行:

df2 = df2[!is.na(df2[,2]),]

(大卫的答案出现在我打字的时候,可能是一种更好的方法,但我认为你可能想知道expand.grid无论如何。)