R:如何根据另一个变量中的值选择dplyr::distinct()保留的行?
现实生活中的问题:我的受试者有核磁共振扫描数据。其中一些已被扫描多次(单独的行)。其中一些人每次都按照不同的协议进行扫描。我想按主题ID保留所有唯一的行,如果一个主题是在两种不同的协议下扫描的,我希望它更喜欢其中一种 玩具示例:R:如何根据另一个变量中的值选择dplyr::distinct()保留的行?,r,dplyr,unique,distinct-values,R,Dplyr,Unique,Distinct Values,现实生活中的问题:我的受试者有核磁共振扫描数据。其中一些已被扫描多次(单独的行)。其中一些人每次都按照不同的协议进行扫描。我想按主题ID保留所有唯一的行,如果一个主题是在两种不同的协议下扫描的,我希望它更喜欢其中一种 玩具示例: library(dplyr) df <- tibble( id = c("A", "A", "B", "C", "C", "D"), protocol = c("X", "Y", "X", "X", "X", "Y"),
library(dplyr)
df <- tibble(
id = c("A", "A", "B", "C", "C", "D"),
protocol = c("X", "Y", "X", "X", "X", "Y"),
date = c(seq(as.Date("2018-01-01"), as.Date("2018-01-06"),
by="days")),
var = 1:6)
如果我有多个协议,并且希望分配一个选择它们的顺序,我可以创建一个新变量,在这个变量中,我按照优先顺序为协议分配一个整数,然后使用@joran的建议
df %>% group_by(id) %>% arrange(desc(protocol),var) %>% slice(1)
谢谢 可能有一种更快的方法(几乎可以肯定是使用data.table),但这将是dplyr中天真的直接方法,我认为:
df %>% group_by(id) %>% arrange(desc(protocol),var) %>% do(head(.,1))
正如@Gregor在下面提到的(现已删除),
slice(1)
对于do(head(,1))
来说可能是一个更好的习惯用法,如果您希望输出是一个不是分组数据的TIBLE,则无需使用group_by()
df %>% arrange(id, desc(protocol)) %>% distinct(id, .keep_all = TRUE)
您可以将此过程分为两个步骤:获取必备项,获取其他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\u preference
变量,以便在Y
不可用的情况下给出您希望选择的顺序,并选择“Y”,即使按字母顺序排序时它不是最后一个协议值
基于@davechilders answer和@Nathan Werth基于“重要性顺序”向量创建因子的想法
在这种情况下,按字母顺序对协议变量进行排序是很方便的,但是在更一般的情况下,例如,如果有一个“Z”协议,但仍然需要选择“Y”,则可以执行
df%>%arrange(id,desc(protocol='Y'))%%>%distinct(id,.keep_all=TRUE)
@RobJensen,这是最简单的答案(到目前为止)。如果你把它作为一个答案发布,我可以选择它。谢谢!当我拿出desc()时,它起了作用。我的真实数据有多个不同的协议和不同的名称。我可以做的是创建另一个变量,在该变量中,我根据偏好为每个协议分配一个数字,然后根据该数字进行排序,并对第一个协议进行切片。感谢!+1在您的第一篇文章中发布了一个清晰描述的问题和期望的结果,以及一个小示例和您尝试过的代码那就发帖吧!干杯。
df %>% arrange(id, desc(protocol)) %>% distinct(id, .keep_all = TRUE)
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)
# 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
order_of_importance <- c("Y", "Z", "X")
df2 %>%
mutate(protocol = factor(protocol, order_of_importance)) %>%
arrange(id, protocol) %>%
distinct(id, .keep_all = TRUE)
df %>%
arrange(id, desc(protocol == 'Y')) %>%
distinct(id, .keep_all = TRUE)