R:如何根据另一个变量中的值选择dplyr :: distinct()保留哪一行?

时间:2018-01-22 20:22:35

标签: r dplyr unique distinct-values

现实生活中的问题:我的受试者有MRI扫描数据。其中一些已被多次扫描(单独的行)。其中一些每次都在不同的协议下进行扫描。我希望按主题ID保留所有唯一的行,如果主题是在两种不同的协议下扫描的,我希望它优先于另一种。

玩具示例:

df %>% distinct(id, .keep_all = TRUE) #Nope! 

df %>% distinct(id, protocol == "Y", .keep_all = TRUE) #Nope!  

df$protocol <- factor(df$protocol, levels = c("Y", "X"))
df %>% distinct(id, .keep_all = TRUE) #Nope!  

df %>% group_by(id) %>% filter(protocol == "Y") #Nope!

我想通过id返回包含所有唯一主题的数据框。当涉及到重复值时,我希望它保留条目#34; Y&#34;而不是自动保留第一个条目。作为协议,如果它有这个选择,但不是摆脱与&#34; X&#34;除此以外。

在示例中,它将保留第2,3,4和6行。

我更喜欢dplyr,但我愿意接受其他建议。

我尝试过的任何事情都没有开始发挥作用:

df %>% arrange(id, desc(protocol == 'Y')) %>% distinct(id, .keep_all = TRUE)  

两个好的答案: @RobJensen建议

df %>% group_by(id) %>% arrange(desc(protocol),var) %>% slice(1)  

如果我有多个协议并希望分配一个它们将被选择的顺序,我可以创建一个新变量,我按优先顺序为协议分配一个整数,然后使用@joran中的建议

{{1}}

谢谢!

4 个答案:

答案 0 :(得分:4)

按照字母顺序排列适用于所述的简单案例,但如果您愿意,可以添加protocol_preference变量,以便在Y不是&#39时对您选择的内容进行排序; t可用,并选择&#34; Y&#34;即使它不是按字母顺序排序的最后一个协议值。

建立@davechilders的答案和@Nathan Werth的想法,创建一个基于&#34;重要性顺序的因素&#34;矢量

order_of_importance <- c("Y", "Z", "X")

    df2 %>%
      mutate(protocol = factor(protocol, order_of_importance)) %>%
      arrange(id, protocol) %>%
      distinct(id, .keep_all = TRUE)

或者,如果您只是想选择&#39; Y&#39;并且如果&#39; Y&#39;并且没有选择所选的内容。你不能做任何事情

df %>% 
    arrange(id, desc(protocol == 'Y')) %>% 
    distinct(id, .keep_all = TRUE)

答案 1 :(得分:3)

这可能是一种更快的方式(几乎可以肯定是data.table),但这是 dplyr 中的天真直接方法我认为:

df %>% group_by(id) %>% arrange(desc(protocol),var) %>% do(head(.,1))

正如下面提到的@Gregor(现已删除),slice(1)可能是do(head(.,1))更好的习语。

答案 2 :(得分:1)

如果您希望输出为不是grouped_df的tibble,则可以在不使用group_by()的情况下实现此目的。

df %>% arrange(id, desc(protocol)) %>% distinct(id, .keep_all = TRUE)

答案 3 :(得分:0)

你可以将这个过程分解为两个步骤:抓住必备品,抓住其他ID的任何内容,然后合并。

distinct_y <- df %>%
  filter(protocol == "Y") %>%
  distinct(id, .keep_all = TRUE)

distinct_other <- df %>%
  anti_join(distinct_y, "id") %>%
  distinct(id, .keep_all = TRUE)

distinct_combined <- rbind(distinct_y, distinct_other)

如果您想将其从“最重要的”推广到价值排序,我建议将protocol作为一个因素。

例如,假设有三个协议:X,Y和Z.Y是最好的,Z优于X,如果没有更好的话,你只需要X.

# Only difference is the best protocol for C will now be Z.
df2 <- tibble(
  id = c("A", "A", "B", "C", "C", "D"),
  protocol = c("X", "Y", "X", "X", "Z", "Y"),
  date = c(seq(as.Date("2018-01-01"), as.Date("2018-01-06"),
               by="days")),
  var = 1:6
)

order_of_importance <- c("Y", "Z", "X")

df2 %>%
  mutate(protocol = factor(protocol, order_of_importance)) %>%
  group_by(id) %>%
  arrange(protocol) %>%
  slice(1)
# # A tibble: 4 x 4
# # Groups: id [4]
#   id    protocol date         var
#   <chr> <fctr>   <date>     <int>
# 1 A     Y        2018-01-02     2
# 2 B     X        2018-01-03     3
# 3 C     Z        2018-01-05     5
# 4 D     Y        2018-01-06     6