使用 ID 列展平数据框中的列表列
Flatten list column in data frame with ID column
我的数据框包含 select 多问题类型的调查的输出。有些单元格有多个值。
df <- data.frame(a=1:3,b=I(list(1,1:2,1:3)))
df
a b
1 1 1
2 2 1, 2
3 3 1, 2, 3
我想展开列表以获得以下输出:
df
a b
1 1 1
2 2 1
3 2 2
4 3 1
5 3 2
6 3 3
应该很容易,但不知何故我找不到搜索词。谢谢。
您可以只使用 "tidyr" 中的 unnest
:
library(tidyr)
unnest(df, b)
# a b
# 1 1 1
# 2 2 1
# 3 2 2
# 4 3 1
# 5 3 2
# 6 3 3
使用 base R
,一个选项是 stack
在将 'b' 列的 list
元素命名为 'a' 的元素之后。我们可以使用 setNames
来更改名称。
stack(setNames(df$b, df$a))
或者另一种选择是使用 unstack
自动将 'b' 的列表元素命名为 'a' 元素,然后执行 stack
以获得 data.frame
输出。
stack(unstack(df, b~a))
或者我们可以使用 splitstackshape
中的便捷函数 listCol_l
将 list
转换为 data.frame
。
library(splitstackshape)
listCol_l(df, 'b')
这是一种方法,data.table
:
require(data.table)
data.table(df)[,as.integer(unlist(b)),by=a]
如果b
一致存储,as.integer
可以跳过。您可以查看
unique(sapply(df$b,class))
# [1] "numeric" "integer"
这是另一个基本解决方案,远不如迄今为止发布的任何其他解决方案优雅。为了完整起见,尽管我个人会推荐 akrun 的基本解决方案。
with(df, cbind(a = rep(a, sapply(b, length)), b = do.call(c, b)))
这会将第一列构造为 a
的元素,其中每个元素都会重复以匹配 b
中相应列表项的长度。第二列是 b
"flattened" using do.call()
with c()
.
正如 Ananda Mahto 在评论中指出的那样,在最新版本的 R(3.2,如果我没记错的话)中,sapply(b, length)
可以替换为 lengths(b)
。
基础 R 方法也可能是为每一行创建一个新的 data.frame
,然后 rbind
:
df <- data.frame(a=1:3,b=I(list(1,1:2,1:3)))
df
df <- lapply(seq_along(df$a), function(x){data.frame(a = df$a[[x]], b = df$b[[x]])})
df <- do.call("rbind", df)
df
我的数据框包含 select 多问题类型的调查的输出。有些单元格有多个值。
df <- data.frame(a=1:3,b=I(list(1,1:2,1:3)))
df
a b
1 1 1
2 2 1, 2
3 3 1, 2, 3
我想展开列表以获得以下输出:
df
a b
1 1 1
2 2 1
3 2 2
4 3 1
5 3 2
6 3 3
应该很容易,但不知何故我找不到搜索词。谢谢。
您可以只使用 "tidyr" 中的 unnest
:
library(tidyr)
unnest(df, b)
# a b
# 1 1 1
# 2 2 1
# 3 2 2
# 4 3 1
# 5 3 2
# 6 3 3
使用 base R
,一个选项是 stack
在将 'b' 列的 list
元素命名为 'a' 的元素之后。我们可以使用 setNames
来更改名称。
stack(setNames(df$b, df$a))
或者另一种选择是使用 unstack
自动将 'b' 的列表元素命名为 'a' 元素,然后执行 stack
以获得 data.frame
输出。
stack(unstack(df, b~a))
或者我们可以使用 splitstackshape
中的便捷函数 listCol_l
将 list
转换为 data.frame
。
library(splitstackshape)
listCol_l(df, 'b')
这是一种方法,data.table
:
require(data.table)
data.table(df)[,as.integer(unlist(b)),by=a]
如果b
一致存储,as.integer
可以跳过。您可以查看
unique(sapply(df$b,class))
# [1] "numeric" "integer"
这是另一个基本解决方案,远不如迄今为止发布的任何其他解决方案优雅。为了完整起见,尽管我个人会推荐 akrun 的基本解决方案。
with(df, cbind(a = rep(a, sapply(b, length)), b = do.call(c, b)))
这会将第一列构造为 a
的元素,其中每个元素都会重复以匹配 b
中相应列表项的长度。第二列是 b
"flattened" using do.call()
with c()
.
正如 Ananda Mahto 在评论中指出的那样,在最新版本的 R(3.2,如果我没记错的话)中,sapply(b, length)
可以替换为 lengths(b)
。
基础 R 方法也可能是为每一行创建一个新的 data.frame
,然后 rbind
:
df <- data.frame(a=1:3,b=I(list(1,1:2,1:3)))
df
df <- lapply(seq_along(df$a), function(x){data.frame(a = df$a[[x]], b = df$b[[x]])})
df <- do.call("rbind", df)
df