根据索引列表从数据框列中提取

时间:2016-09-02 17:20:47

标签: r dataframe subset

我有一个数据框:

df = read.table(text="ID    location    C1  C2  C3  C4  C5  C6
M01 1   A   H   H   A   A   B
M02 2   A   H   A   A   A   B
M03 3   A   B   A   A   A   B
M04 4   H   B   H   A   A   B
M05 5   H   B   H   A   A   B
M06 6   A   B   H   A   A   H
M07 7   A   B   H   B   A   H
M08 8   A   B   H   A   A   H
M09 9   A   B   H   A   A   H
M10 10  B   B   H   A   A   H
M11 11  A   B   H   A   A   H
M12 12  A   B   H   A   A   H
M13 13  A   B   H   A   A   H
M14 14  B   B   B   A   A   H
M15 15  B   B   B   A   A   A", header=T, stringsAsFactors=F)

我想根据df$ID的索引行号列表提取df的值。列表a是:

a = list(C1 = c(3,   5,   9,   10,  13), C2 = c(2) , 
C3 = c(1,   3,   13 ), C4 =c(6,   7 ), C6 = c(5,   14 ))

预期结果是:

$C1
[1] "M03" "M05" "M09" "M10" "M13"

$C2
[1] "M02"

$C3
[1] "M01" "M03" "M13"

$C4
[1] "M06" "M07"

$C6
[1] "M05" "M14"

2 个答案:

答案 0 :(得分:7)

您可以取消列出a列表,索引数据值,然后relist将其自身作为骨架。

relist(df$ID[unlist(a)], a)
# $C1
# [1] "M03" "M05" "M09" "M10" "M13"
#
# $C2
# [1] "M02"
#
# $C3
# [1] "M01" "M03" "M13"
#
# $C4
# [1] "M06" "M07"
#
# $C6
# [1] "M05" "M14"

此外,如果我们删除unlist中的名称,我们可以提高速度。

relist(df$ID[unlist(a, use.names = FALSE)], a)

注意:

另一个答案的基准是误导性的。这是更准确的基准测试,显示了另一个答案的实际代码,该答案在每次迭代时使用$提取并删除表达式周围不必要的{}括号... < / p>

df <- data.frame(v1 = paste0("M", 1:1e6))
set.seed(24)
a1 <- lapply(1:1e4, function(i) sample(1:1e6, sample(1e3), replace=FALSE))

system.time(relist(df$v1[unlist(a1, use.names = FALSE)], a1))
#   user  system elapsed 
#  0.485   0.004   0.489 
system.time(lapply(a1, function(x) df$v1[x]))
#   user  system elapsed 
#   0.39    0.00    0.39 

答案 1 :(得分:3)

这可以通过循环lapply并{0}提取list来轻松完成。基于每个list元素

中的索引
lapply(a, function(x) df$ID[x])
#$C1
#[1] "M03" "M05" "M09" "M10" "M13"

#$C2
#[1] "M02"

#$C3
#[1] "M01" "M03" "M13"

#$C4
#[1] "M06" "M07"

#$C6
#[1] "M05" "M14"

或者我们可以使用Map的紧凑选项来完成工作

Map(`[`, list(df$ID), a)
#[[1]]
#[1] "M03" "M05" "M09" "M10" "M13"

#[[2]]
#[1] "M02"

#[[3]]
#[1] "M01" "M03" "M13"

#[[4]]
#[1] "M06" "M07"

#[[5]]
#[1] "M05" "M14"

nchar("Map(`[`, list(df$ID), a)")
#[1] 24

基准

此处,基准测试基于vector(&#39; v1&#39;)和list(&#39; a1&#39;)。

v1 <- paste0("M", 1:1e6)

如果是data.frame列(v1 <- someDat$ID),以避免重复提取。

set.seed(24)
a1 <- lapply(1:1e4, function(i) sample(1:1e6, sample(1e3), replace=FALSE))

system.time(relist(v1[unlist(a1, use.names = FALSE)], a1))
# user  system elapsed 
# 0.81    0.03    0.84 


system.time(lapply(a1, function(x) v1[x]))
# user  system elapsed 
#   0.36    0.00    0.36 

system.time(Map(`[`, list(v1), a1))
#  user  system elapsed 
#  0.35    0.00    0.34 

注意:删除了{}(我们之前忽略了这一点),但基准测试中仍然没有太大变化。如前所述,最好创建一个矢量对象(v1 <- someDat$ID)并使用它来检查基准,而不是每次都提取列。在这方面,该基准测试符合准确基准测试的目的。