根据一列中的最大值和唯一值筛选行

4

期望输出这有点棘手,我会尽力解释,如下所述。 我有以下数据框。 我需要根据国家列中的最大pop过滤行组,但是该组尚未出现在上述组中。(根据输出(图像),之所以A没有出现在第二组中,是因为它已经出现在第一组中)

简而言之,我需要获取国家列中的唯一值,同时在组级别上获取pop的最大值。 希望图片可以传达我无法表达的内容。(首选Tidyverse方案)

[![期望输出][2]][2]

df<- structure(list(Group = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), country = c("A", "B", "C", "A", "E", "F", "A", "E", "G"), pop = c(200L, 100L, 50L, 200L, 150L, 120L, 200L, 150L, 
100L)), class = "data.frame", row.names = c(NA, -9L))

如果G也出现在A组,并且其值为150,那么最终结果会是一样的吗?因此,如果一个国家在一个组中“输了”,它能否在另一个值较低的组中“赢”呢? - Harlan Nelson
我认为OP只想在下一次迭代中消除国家。它的pop值并不重要!让Vaibhav澄清。 - AnilGoyal
4个回答

4

我认为这样做可以。语法解释如下:

  • 将数据拆分成每个组的列表
  • 保留第一组(因为它将在下一步中用作.init,但在过滤pop值的最大值之后)。
  • 在此处使用purrr::reduce,它将把tibbles的列表减少到单个tibble。
  • reduce中使用的迭代:
    • .init 作为经过过滤的第一组
    • 然后通过anti_join删除前面组中的国家
    • 再次过滤这些数据以获取最大的pop
    • 通过bind_rows()添加先前过滤的国家
  • 因此,最终我们将得到所需的tibble。
df %>% group_split(Group) %>% .[-1] %>%
  reduce(.init =df %>% group_split(Group) %>% .[[1]] %>% 
               filter(pop == max(pop)), 
             ~ .y  %>%
               anti_join(.x, by = c("country" = "country")) %>% 
               filter(pop == max(pop)) %>%
               bind_rows(.x) %>% arrange(Group)) 

# A tibble: 3 x 3
  Group country   pop
  <int> <chr>   <int>
1     1 A         200
2     2 E         150
3     3 G         100

Edited (Corrected it) - Vaibhav Singh
这也适用于一个国家在一个不是最高的组中具有更高的价值的情况。 - Harlan Nelson

2
你可以创建一个辅助函数,将每个组的最大值写入向量,并使用它来过滤数据框。
library(tidyverse)
max_values <- c()

helper <- function(dat, ...){
  dat <- dat[!(dat %in% max_values)] # exclude maximum values from previous groups
  max_value <- max(dat) # get current max. value
  max_values <<- c(max_values, max_value) # append 
  return(max_value)
}

df %>% 
  group_by(Group) %>% 
  filter(pop == helper(pop))

这将为您提供:

# A tibble: 3 x 3
# Groups:   Group [3]
  Group country   pop
  <int> <chr>   <int>
1     1 A         200
2     2 E         150
3     3 H         120

使用的数据:

> df
   Group country pop
1      1       A 200
2      1       B 100
3      1       C  50
4      2       A 200
5      2       E 150
6      2       F 120
7      3       A 200
8      3       E 150
9      3       G 100
10     3       H 120

即使一个国家在一个组中不是最高的,这也适用。 - Harlan Nelson
这需要使用全局变量(<<-写入父环境)。通常情况下,最好不要这样做。 - crestor

0

这里还有另一种可能性,但是过于简化了,因为它没有考虑到一个群体在一个它没有赢得的群体中拥有更高的人口的可能性。

library(dplyr)
df<- structure(list(Group = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), country = c("A", "B", "C", "A", "E", "F", "A", "E", "G"), pop = c(200L, 100L, 50L, 200L, 150L, 120L, 200L, 150L, 
100L)), class = "data.frame", row.names = c(NA, -9L))

df %>% 
  group_by(country) %>% 
  summarize(popmax = max(pop))  %>% 
  inner_join(df, by = c("popmax" = 'pop')) %>% 
  rename(country = country.y) %>% 
  select(-country.x) %>% 
  group_by(country) %>% 
  arrange(Group) %>% 
  slice(1) %>% 
  ungroup() %>% 
  group_by(Group) %>% 
  arrange(country) %>% 
  slice(1) %>%  
  select(Group, country, popmax) %>% 
  rename(pop = popmax)

我的答案在这个数据集上失败了(而其他答案没有):

df <- tribble(
  ~Group, ~ country, ~pop,
  1     ,         'A',    200,
  1     ,         'B',    100,
  1     ,         'C',     50,
  1     ,         'G',    150,
  2     ,         'A',    200,
  2     ,         'E',    150,
  2     ,         'F',    120,
  3     ,         'A',    200,
  3     ,         'E',    150,
  3     ,         'G',    100
)

-1

更新 @Crestor声称我的答案不正确。

  • 我的答案是正确的,因为我的代码按照OP要求给出了预期的输出。

  • 你对我的代码在另一种情况下无法运行的反驳可能是正确的,但在这种情况下它是无关紧要的,因为我的答案只旨在解决手头的任务。

  • 这是针对你提出的数据集场景的答案:

df1 <- structure(list(Group = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), 
    country = c("A", "B", "C", "A", "E", "F", "A", "E", "G"), 
    pop = c(200L, 100L, 250L, 220L, 150L, 120L, 200L, 150L, 100L
    )), row.names = c(NA, -9L), class = c("tbl_df", "tbl", "data.frame"
))

预期产出由Crestor:

# A tibble: 3 x 3
  Group country   pop
  <int> <chr>   <int>
1     1 C         250
2     2 A         220
3     3 E         150

针对您的情况,这是我的代码 @crestor

library(dplyr)

df1 %>% 
group_by(country) %>% 
arrange(Group) %>% 
filter(pop == max(pop)) %>% 
group_by(Group) %>% 
filter(pop == max(pop)) 

输出:

  Group country   pop
  <int> <chr>   <int>
1     1 C         250
2     2 A         220
3     3 E         150

对于问题的原始回答:

简单来说:首先,arrange将数据集放置在正确的位置。然后使用group_by并使用slice保留每个组中的第一行。接下来,再次使用group_by Group并使用filter筛选出最大的pop

library(dplyr)
df %>% 
  arrange(country, pop) %>% 
  group_by(country) %>% 
  slice(1) %>% 
  group_by(Group) %>% 
  filter(pop==max(pop))

输出:

  Group country   pop
  <int> <chr>   <int>
1     1 A         200
2     2 E         150
3     3 G         100

一个问题是:为什么在你的代码中,A被放在第1组?这似乎与它之前在第1组而不是第2组无关。但如果组顺序打破了平局,而不是国家顺序呢? - Harlan Nelson
感谢您宝贵的评论。AGroup1的一部分。无论在这种情况下后续的A放在哪里都没有关系。在第一个最大出现次数之后的国家都是无关紧要的,因为假设是:“国家列中的最大人口,但在上述组中尚未发生”。这种逻辑需要跳出常规思维,除非有其他证明,否则这种方法似乎是可行的。 - TarJae
答案是针对问题具体的。对于您的数据集更改:将 group_by(country) 更改为 group_by(country, pop)。让我知道您的想法?干杯。 - TarJae
请使用此数据集进行检查。df1 <- structure(list(Group = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L), country = c("A", "B", "C", "A", "E", "F", "A", "E", "G", "G", "E", "I"), pop = c(200L, 100L, 250L, 220L, 150L, 120L, 200L, 150L, 100L, 100L, 150L, 98L )), row.names = c(NA, -12L), class = c("tbl_df", "tbl", "data.frame" )) 实际上,给定的代码只有3个组,并且您进行了2次筛选。对于n个组,按照您的策略,您需要进行n-1次筛选。 - AnilGoyal
@AnilGoyal。非常感谢您的时间。为了保持概述,我们应该达成以下共识:1.在这种特殊情况下,我的第一个代码可以带来OP所需的结果。2. Crestor是正确的,它在另一个数据集中不起作用。3.因此,我提供了我的第二个代码,适用于Crestor的数据集,在这个数据集中,这个代码也带来了所需的结果。4.现在出现了第三个数据集(AnilGoyal)。5.如果有人成功地向我展示上述任何一个答案(AnilGoyal、SEcker、Harlan Nelson)都适用于所有3个数据集(第1个OP、第2个Crestor、第3个AnilGoyal),我会收回我的说法。 - TarJae
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接