【问题标题】:How to delete duplicates from groups in R where group is formed by three columns如何从R中的组中删除重复项,其中组由三列组成
【发布时间】:2016-12-17 02:39:23
【问题描述】:

假设我们有一个这样的数据框:

PatientID   BookingID   Level1   Level2  Value 
a1           101-A1        1     HBA1C   9.4
a2           102-A2        1     LDL     116
a1           101-A1        1     VLDL    11
a1           101-A1        2     POL     10
a1           102-A1        1     HBA1c   9.4
a2           102-A2        1     VLDL    10
a1           102-A1        1     VLDL    11
a2           103-A2        1     LDL     116
a2           103-A2        1     VLDL    11
a1           102-A1        2     POL     10

这个想法是,患者(唯一患者 ID)可以来到实验室并接受一组条件的测试 - 更广泛的测试类别是 level1,它们的子类别是 level2(level1 与 level2 具有一对多的关系),现在,患者 ID 的 BookingId 列可能因访问日期不同而有所不同。 value 列表示每个测试的值(Patient ID 与 BookingID 具有一对多关系)。

所以一个组由“level1”、“patientID”及其“Value”的一个组合组成,如果 patientID a1 来了两次进行自我测试 - 101-A1 和 102-A1如果所有测试值都相同,则只保留其中一个,如果有任何变化,例如 patientID a2 的情况,则所有值都保留,因此我们需要这样的 o/p:

PatientID   BookingID   Level1   Level2  Value 
a1           101-A1        1     HBA1C    9.4
a2           102-A2        1      LDL     116
a1           101-A1        1      VLDL    11
a1           101-A1        2      POL     10
a2           102-A2        1      VLDL    10
a2           103-A2        1      LDL     116
a2           103-A2        1      VLDL    11

我尝试使用 Dplyr 包中的以下代码,但那是删除我们想要的东西:

abcTest1 <- FullData %>% group_by(level1, patientId, value) %>% slice(1)

我似乎无法正确执行此操作,请提供输入

【问题讨论】:

  • 请问您为什么在问题中添加标签mysqlexcelsqlite?这个问题似乎与其中任何一个都无关。我可能会选择 uniquesubsetdataframe
  • @Barker 我可以选择在任何工具上执行此操作,因为 sqldf 包支持 sql 语法
  • 麻烦您使用一致的列名。无论如何,为此的 dplyr 函数是 DF %&gt;% distinct(Level1, PatientID, Value)

标签: r dataframe dplyr unique


【解决方案1】:

你也可以这样做:

library(dplyr)
> df
# A tibble: 10 × 5
   PatientID BookingID Level1 Level2 Value
       <chr>     <chr>  <dbl>  <chr> <dbl>
1         a1    101-A1      1  HBA1C   9.4
2         a2    102-A2      1    LDL 116.0
3         a1    101-A1      1   VLDL  11.0
4         a1    101-A1      2    POL  10.0
5         a1    102-A1      1  HBA1c   9.4
6         a2    102-A2      1   VLDL  10.0
7         a1    102-A1      1   VLDL  11.0
8         a2    103-A2      1    LDL 116.0
9         a2    103-A2      1   VLDL  11.0
10        a1    102-A1      2    POL  10.0
> df %>% distinct(PatientID, Level1, Value, .keep_all=TRUE)
# A tibble: 6 × 5
  PatientID BookingID Level1 Level2 Value
      <chr>     <chr>  <dbl>  <chr> <dbl>
1        a1    101-A1      1  HBA1C   9.4
2        a2    102-A2      1    LDL 116.0
3        a1    101-A1      1   VLDL  11.0
4        a1    101-A1      2    POL  10.0
5        a2    102-A2      1   VLDL  10.0
6        a2    103-A2      1   VLDL  11.0

与@Barker 的回答一样,这不包括最后的116.0 行,但那是因为您的逻辑不成立。您声明“如果患者 ID a1 来了两次以进行自己的测试 - 101-A1 和 102-A1 并且如果所有测试值都相同,则只剩下其中一个”,我们在第 1 行和第 5 行中看到,在您的预期输出仅保留第 1 行。但是,完全相同的逻辑适用于第 2 行和第 8 行,但您希望保留这两行。

基于评论的新答案

好的,我终于明白你在说什么,并且能够破译正确删除重复数据所需的规则。这是一个复杂的过程,但看起来像这样:

library(dplyr)
library(stringr)
library(tidyr)
df %>% 
  group_by(PatientID, BookingID) %>% 
  mutate(Key = paste(Level1, Level2, Value, collapse=";")) %>% 
  ungroup() %>% 
  select(-Level1, -Level2, -Value) %>% 
  distinct(PatientID, Key, .keep_all=TRUE) %>% 
  mutate(Key = str_split(Key, ";")) %>% 
  unnest(Key) %>% 
  separate(Key, into=c("Level1", "Level2", "Value"), 
           sep=" ", remove=TRUE) %>%
  arrange(PatientID, BookingID, Level1, Level2)

# A tibble: 7 × 5
  PatientID BookingID Level1 Level2 Value
*     <chr>     <chr>  <chr>  <chr> <chr>
1        a1    101-A1      1  HBA1C   9.4
2        a1    101-A1      1   VLDL    11
3        a1    101-A1      2    POL    10
4        a2    102-A2      1    LDL   116
5        a2    102-A2      1   VLDL    10
6        a2    103-A2      1    LDL   116
7        a2    103-A2      1   VLDL    11

基本上,我们首先将我们最感兴趣的三个值 Level1Level2Value 放入一个字符串中,在其中我们将每个 @987654327 的每组值分开@ 用分号。这将为我们提供PatientID == a1PatientID == a2 的两行信息,总共四行。然后我们仅通过PatientIDKey 进行重复数据删除,但同时告诉R 保留BookingID。我们发现a1 的数据相同,但a2 的数据不同,因为Value 其中Level2 == POL 在两次访问中都不相同。因此,在我们进行重复数据删除之后,我们只剩下三行。然后,我们使用分号作为分隔符拆分Key,然后将separate 拆分为Key 变量以取回我们原来的列。

【讨论】:

  • 将级别 1 视为广泛的类别,例如亚马逊上的电子产品 - 有笔记本电脑、手机等产品(级别 2), - 说级别 1 有 50 个级别 2 测试,那么对于一个患者 ID,将有重复 50 个 bookingIds - 每个在“value”列中都有其值。所以如果一个病人来了三次,会有 3 个 bookingID 重复 50 次,我们需要将这组 50 个值与其他两组 50 个值进行比较。只有当我们发现一个组中的所有 50 个值都匹配其他两组时,我们才删除。否则,即使是一种变化,所有价值仍然存在
  • bookingID 的值会随着单个患者 ID 的不同访问而变化。您建议的答案是我最初想到的,但这会导致不必要的删除。请检查我粘贴的代码
  • 那么因为101-A1包含了“HBA1C”、“LDL”、“POL”三个值,和102-A1一样,我们可以删除102-A1的所有值吗?这种逻辑仍然无法与数据保持一致。在你能清楚地描述演绎背后的规则之前,我认为没有人能帮助你。
  • 不要这么想——对于一个特定的patientId a1——有两个bookingId——101-A1和102-A1,如果所有相关值都是101-A1,也就是测试值对于 HBA1C、LDL 和 POL,如果它们与第二个 bookingID 102-A1 中的所有值匹配,那么我们只保留特定患者的第一个 bookingId 值。
  • @Rohan 我已经更新了我的答案,这应该可以满足您的需求。
【解决方案2】:

这是duplicated() 函数的经典用法。此函数确定向量或数据框的唯一元素,并返回一个逻辑值,指示在对象中较早看到哪些元素。在这种情况下,我们可以在要查找其唯一元素的数据框列上使用duplicated(),并使用输出进行索引。

> df[!duplicated(df[c("PatientID", "Level1", "Value")]), ]
  PatientID BookingID Level1 Level2 Value
1        a1    101-A1      1  HBA1C   9.4
2        a2    102-A2      1    LDL 116.0
3        a1    101-A1      1   VLDL  11.0
4        a1    101-A1      2    POL  10.0
6        a2    102-A2      1   VLDL  10.0
9        a2    103-A2      1   VLDL  11.0

我的输出与您的略有不同,因为第二行的值为 116 不存在,但根据您的描述,我认为这是示例中的错误。

【讨论】:

  • 请正确理解问题 - 患者 ID a2 在最后一列“11”中的 vldl 具有一个不同的值,因此该患者 ID 的特定级别 1 的所有其他值需要保持不变,因此第二行使用需要值 116
  • @Rohan 你想要的是什么;如果PatientIDLevel1 的所有唯一组合具有相同的Value,则返回PatientIDLevel1 的唯一值;否则返回 PatientID 的所有数据?
  • 是的,这个想法是,如果患者来并接受了三次级别 1 测试 - 并且说级别 1 有 20 个不同的测试(由级别 2 显示),所以如果在所有 20*3 条目中,值前 20 个重复 3 次,然后我们取唯一值,否则即使有一个不匹配,我们也会保留所有信息
  • 这样一个步骤的问题是,如果有一个非常大的数据集......那么即使整个 level2 测试的 level1 值可能不同 - 但如果某些 level2 值相同,那些将被淘汰 - 尽管他们将属于同一级别1
【解决方案3】:

您可以通过简单地使用 unique 来做到这一点

PatientID <- c("a1","a2","a1")
BookingID <- c("num1","num2","num1")
Level1 <- c(1,2,1)
Level2 <- c("HBA", "CDA", "HBA")
Value <- c(10,4,10)

df <- data.frame(PatientID,BookingID,Level1,Level2,Value)
df <- unique(df)

【讨论】:

  • 我认为这行不通,因为unique() 会查看所有列,而BookingIDLevel2 列会导致问题。
  • Barker,但问题要求它在所有列中都应该是唯一的,不是吗?
  • 巴克,会造成什么样的问题,能不能运行一下我的代码检查一下,可重现
  • 根据提问者 " 一个组由 'level1'、'patientID' 和它的 'Value' 的一个组合组成,如果 PatientID a1 来了两次以进行自己的测试 - 101- A1 和 102-A1,如果所有测试值都相同,则仅保留其中一个”,因此只有 Level1PatientIDValue 重要,而不是 BookingIDLevel2 .您的示例之所以有效,是因为您在不同的数据上使用它。我在询问者的数据上运行它,没有任何内容被删除。您可以使用read.table(text = "copyAndPasteTextHere", header = TRUE) 轻松读取他们的数据。
  • @Barker 你能推荐点别的吗
【解决方案4】:

使用出色的 data.table 包,这很容易以简单的方式完成:

install.packages("data.table")
library(data.table)
FullData %<>% as.data.table

abcTest1 <- FullData %>% unique(by = c("level1", "patientId", "value"))

【讨论】:

  • 哎呀,添加库(magrittr)
  • abcTest1 % unique(by = ("level1", "patientId", "value")) 错误:“abcTest1 % unique( by = ("level1","
  • 嘿安德鲁,你能解释一下你的代码和我的代码之间的区别吗:abcTest1 % unique(by = c("level1", "patientId", "value")) abcTest1 % group_by(level1, patientId, value) %>% slice(1)
  • 我检查了我的代码得到了和你一样的输出我不认为有区别
猜你喜欢
  • 2015-09-22
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 2019-08-22
  • 2017-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多