【问题标题】:Subset data frame with matrix of logical values具有逻辑值矩阵的子集数据框
【发布时间】:2016-03-09 09:45:50
【问题描述】:

问题

我有四个人的两个测量数据,每个数据都是宽格式的。措施是xy,个人是A, B, C, D。数据框是这样的

d <- data.frame(matrix(sample(1:100, 40, replace = F), ncol = 8))
colnames(d) <- paste(rep(c("x.", "y."),each = 4), rep(LETTERS[1:4], 2), sep ="")
d

  x.A x.B x.C x.D y.A y.B y.C y.D
1  56  65  42  96 100  76  39  26
2  19  93  94  75  63  78   5  44
3  22  57  15  62   2  29  89  79
4  49  13  95  97  85  81  60  37
5  45  38  24  91  23  82  83  72

现在,我想为每一行获取y 的值,对于具有最低值x 的个人。

因此,在上面的示例中,1 行中x 的最小值是针对单个C。因此,对于行1,我想获得y.C,即39

在示例中,结果向量应为39, 63, 89, 81, 83

接近

我试图通过首先为x 的值生成d 子集的矩阵来解决此问题。

t(apply(d[,1:4], 1, function(x) min(x) == x))

       x.A   x.B   x.C   x.D
[1,] FALSE FALSE  TRUE FALSE
[2,]  TRUE FALSE FALSE FALSE
[3,] FALSE FALSE  TRUE FALSE
[4,] FALSE  TRUE FALSE FALSE
[5,] FALSE FALSE  TRUE FALSE

现在我想将此矩阵应用于数据框子集的子集,以获取 y 的值。但我找不到实现这一目标的方法。

非常感谢任何帮助。也非常欢迎提出完全不同的、更优雅的方法的建议。

非常感谢!

【问题讨论】:

  • 您可以使用布尔掩码直接对y 值集进行子集化:d[,5:8][t(apply(d[,1:4], 1, function(x) min(x) == x))]
  • 您可以查看以下解决方案。与您帖子中的apply 方法相比,它应该更快
  • @alistaire 该方法不会以正确的顺序给出预期的输出。我会使用t(d[,5:8])[apply(d[,1:4], 1, function(x) min(x) == x)]

标签: r matrix dataframe subset logical-operators


【解决方案1】:

我们使用以“x”(“dx”)和“y”(“dy”)开头的列对数据集进行子集化。使用max.colcbind和行索引获取'dx'每一行中最小值的列索引,并获取'dy'中对应的元素。

 dx <- d[grep('^x', names(d))]
 dy <- d[grep('^y', names(d))]
 dy[cbind(1:nrow(dx),max.col(-dx, 'first'))]
 #[1] 39 63 89 81 83

上面可以很容易地转换成函数

 get_min <- function(dat){
     dx <- dat[grep('^x', names(dat))]
     dy <- dat[grep('^y', names(dat))]
     dy[cbind(1:nrow(dx), max.col(-dx, 'first'))]
   }
get_min(d)
#[1] 39 63 89 81 83

或者使用 OP 的基于 apply 的方法

t(d[,5:8])[apply(d[,1:4], 1, function(x) min(x) == x)] 
#[1] 39 63 89 81 83

数据

d <- structure(list(x.A = c(56L, 19L, 22L, 49L, 45L),
x.B = c(65L, 
93L, 57L, 13L, 38L), x.C = c(42L, 94L, 15L, 95L, 24L), 
x.D = c(96L, 
75L, 62L, 97L, 91L), y.A = c(100L, 63L, 2L, 85L, 23L), 
y.B = c(76L, 
78L, 29L, 81L, 82L), y.C = c(39L, 5L, 89L, 60L, 83L), 
y.D = c(26L, 
44L, 79L, 37L, 72L)), .Names = c("x.A", "x.B", "x.C", 
"x.D", 
"y.A", "y.B", "y.C", "y.D"), class = "data.frame", 
row.names = c("1", "2", "3", "4", "5"))

【讨论】:

  • 非常感谢。 max.col 对我来说是新的。虽然我更喜欢使用apply 的单行方法。鉴于我的数据框的大小,性能不是问题。
【解决方案2】:

这是我的解决方案。核心思想是有函数which.min, which.max可以行应用于数据框:

编辑:

现在,我想为每一行获取 y 的值 x 值最低的个体。

ind <- apply(d[ ,1:4], 1, which.min) # build column index by row
res <- d[,5:8][cbind(1:nrow(d), ind)] # rows are in order, select values by matrix
names(res) <- colnames(d)[5:8][ind] # set colnames as names from the sample column
res 
y.D y.B y.D y.A y.D
18  46  16  85  80

警告:仅当个体在治疗 x 的顺序相同时才有效。和y。和所有在场的人。否则,您可以像 Akrun 的解决方案一样使用 grep。

# My d was:

   x.A x.B x.C x.D y.A y.B y.C y.D
1  88  96  65  55  14  99  63  18
2  12  11  27  45  70  46  20  69
3  32  81  21   9  77  44  91  16
4   8  84  42  78  85  94  28  90
5  31  51  83   2  67  25  54  80

【讨论】:

    【解决方案3】:

    我们可以如下创建一个函数,

    get_min <- function(x){
      d1 <- x[,1:4]
      d2 <- x[,5:8]
      mtrx <- as.matrix(d2[,apply(d1, 1, which.min)])
      a <- row(mtrx) - col(mtrx)
      split(mtrx, a)$"0" 
    }
    get_min(d)
    #[1] 39 63 89 81 83
    

    【讨论】:

      猜你喜欢
      • 2021-03-22
      • 2018-05-03
      • 1970-01-01
      • 1970-01-01
      • 2015-11-23
      • 1970-01-01
      • 2014-12-04
      • 1970-01-01
      • 2016-03-28
      相关资源
      最近更新 更多