【问题标题】:Select values in a table conditional to an external table以外部表为条件选择表中的值
【发布时间】:2021-06-28 07:58:03
【问题描述】:

我想选择数据集中每个变量(列)的前 N ​​个值,其中 N 因列和行而异,并在另一个表中给出。下面是虹膜数据的示例:

data(iris)
head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

## Create a fake external table
ext.tab <- data.table(species=c("setosa","versicolor", "virginica" ),N1=c(1:3),N2=c(3:5),N3=c(5:7),N4=c(7:9))
head(ext.tab)

      species N1 N2 N3 N4
1:     setosa  1  3  5  7
2: versicolor  2  4  6  8
3:  virginica  3  5  7  9

现在对于 Iris setosa,我想获得第 1 列(虹膜数据中的“sepal.length”)的第一个最大值(ext.tab 中的 N1),然后是三个最大值第 2 列 (sepal.width) 的值 (ext.tab 中的 N2),然后是第 3 列 (petal.length) 的五个最大值 (N3),依此类推。然后移动到 Iris versicolor 并做同样的事情。

结果可以是每个物种的表格或列表,其中包含值本身或每个变量(列)的行索引。有什么快速的实现方法的想法吗?

【问题讨论】:

  • 你的问题我不清楚。您想要的输出应该是什么样的?
  • 嗨,温佩尔。我已经修改了我的答案以澄清所需的输出。

标签: r dplyr data.table


【解决方案1】:

这是使用自定义函数的tidyverse 方法。该函数将变量和组名称作为字符标量,将最大值的数量作为数字。函数内部是一个使用.data pronoundplyr 管道。然后,我将ext.tab 重新整形为长格式并逐行应用get_maximum()

library(tidyverse)

get_maximum <- \(.x, .group, .n_max, .dat) {
  .dat %>% 
    filter(Species == .group) %>% 
    arrange(desc(.data[[.x]])) %>% 
    slice(seq_len(.n_max)) %>% 
    pull(.data[[.x]])
}


dat <- as_tibble(ext.tab) %>%
  pivot_longer(-species) %>%
  mutate(name = recode(
    name,
    N1 = "Sepal.Length",
    N2 = "Sepal.Width",
    N3 = "Petal.Length",
    N4 = "Petal.Width"
  )) %>% 
  rowwise() %>% 
  mutate(max_num = list(
    get_maximum(name, species, value, iris)
  )) %>%
  ungroup()

如果您需要唯一的最大值,您可以在自定义函数中添加distinct()

get_maximum_unique <- \(.x, .group, .n_max, .dat) {
  .dat %>% 
    filter(Species == .group) %>% 
    distinct(.data[[.x]]) %>% 
    arrange(desc(.data[[.x]])) %>% 
    slice(seq_len(.n_max)) %>% 
    pull(.data[[.x]])
}

【讨论】:

  • 谁!感谢您的及时回答 Zaw。看起来是一个非常优雅的解决方案!必须对代码进行一些解释。
  • 在 R 4.1.0 中,我们可以使用 \ 创建一个函数。在早期版本中并非如此。您可以改用它。 get_maximum &lt;- function(.x, .group, .n_max, .dat)。你是对的 - 应该添加一些解释。我已经更新了答案。
【解决方案2】:

这是一个使用data.table 的选项。我冒昧地重命名了列名。

cols <- setdiff(names(ext.tab), "Species")
iris[ext.tab, on=.(Species), by=.EACHI, 
    .(.(mapply(function(x, n) -head(sort(-x, partial=n), n), 
        x=mget(cols), n=mget(paste0("i.", cols)), SIMPLIFY=FALSE)))]$V1

数据:

library(data.table)
iris <- as.data.table(iris)
ext.tab <- data.table(Species=c("setosa", "versicolor", "virginica"),
    Sepal.Length=c(1:3),
    Sepal.Width=c(3:5),
    Petal.Length=c(5:7),
    Petal.Width=c(7:9))

输出:

[[1]]
[[1]]$Sepal.Length
[1] 5.8

[[1]]$Sepal.Width
[1] 4.4 4.2 4.1

[[1]]$Petal.Length
[1] 1.9 1.9 1.7 1.7 1.7

[[1]]$Petal.Width
[1] 0.4 0.4 0.6 0.4 0.5 0.4 0.4


[[2]]
[[2]]$Sepal.Length
[1] 7.0 6.9

[[2]]$Sepal.Width
[1] 3.4 3.3 3.2 3.2

[[2]]$Petal.Length
[1] 5.1 4.8 4.9 5.0 4.9 4.8

[[2]]$Petal.Width
[1] 1.7 1.6 1.6 1.8 1.5 1.5 1.6 1.5


[[3]]
[[3]]$Sepal.Length
[1] 7.7 7.9 7.7

[[3]]$Sepal.Width
[1] 3.8 3.8 3.6 3.4 3.4

[[3]]$Petal.Length
[1] 6.4 6.3 6.7 6.9 6.7 6.6 6.1

[[3]]$Petal.Width
[1] 2.5 2.5 2.4 2.5 2.4 2.4 2.3 2.3 2.3

简短说明:

  1. 执行左连接iris[ext.tab, on=.(Species),
  2. by=.EACHI 表示ext.tab 的每一行
  3. x=mget(cols) 获取 iris 中的列
  4. mget(paste0("i.", cols)) 获取每列所需的值的数量
  5. -head(sort(-x, partial=n), n) 执行部分排序并提取前 n 个值
  6. 只需 SIMPLIFY=FALSE.(.( )) 即可将结果作为列表返回

【讨论】:

  • 谢谢!看起来也很不错。对不起,我只能接受一个答案。一些解释也会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-06
  • 1970-01-01
  • 2011-12-14
  • 2022-07-05
  • 2019-05-19
  • 2018-09-23
  • 2019-05-18
相关资源
最近更新 更多