0

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

>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列转换为一个新的数据框,这样我就可以有一个一对多的关系:

>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

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

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

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

4

3 回答 3

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")]
于 2013-08-01T01:54:47.930 回答
2

concat.split.multiple从我的“splitstackshape”包中,有一个选项可以执行拆分并在一步中进行整形,剩下的唯一一件事就是删除具有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

其他情况下,该功能的“胆量”在速度方面表现相当不错。不过,我从未对这个特定功能进行基准测试(主要是因为我从一开始就从未真正处理过非常大的数据集)。

于 2013-08-01T04:40:30.297 回答
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)

最后,摆脱大卫罗宾逊的回答中的 NA 行:

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

(大卫的答案出现在我打字的时候,可能是一个更好的方法,但我想你可能还是想知道expand.grid。)

于 2013-08-01T02:23:27.453 回答