Как определить зеркальные дубликаты строк в R - PullRequest
0 голосов
/ 13 февраля 2019

В следующем сообщении SO Как определить частичные дубликаты строк в R , я спросил, как избавиться от частично дублированных строк.Вот что я спросил:

Я хотел бы определить «частичные» совпадения строк в кадре данных.В частности, я хочу создать новый столбец со значением 1, если конкретная строка в кадре данных имеет повторяющуюся строку где-то еще в кадре данных на основе соответствия между подмножеством столбцов.Дополнительная сложность заключается в том, что один из столбцов в кадре данных является числовым, и я хочу сопоставить, если абсолютные значения совпадают.

Проблема заключается в том, что мне нужно убедиться, что когда строка определена какчастично дублируется, это ТОЛЬКО, если ОДИН из столбцов, являющихся частью совпадения, является зеркально противоположным значением, а не просто совпадением по абсолютному значению.Чтобы прояснить ситуацию, вот пример данных из предыдущего поста:

name<-c("Richard Nixon", "Bill Clinton", "George Bush", "Richard Nixon")
state<-c("California", "Indiana", "Florida", "California")
num<-c("-258", "123", "42", "258")
date<-c("day 2", "day 15", "day 3","day 45")
(df<-as.data.frame(cbind(name,state,num, date)))
           name      state  num   date
1 Richard Nixon California -258  day 2
2  Bill Clinton    Indiana  123 day 15
3   George Bush    Florida   42  day 3
4 Richard Nixon California  258 day 45 

Вот решение моего предыдущего поста:

df$absnum = abs(as.numeric(as.character(df$num)))
df$newcol = duplicated(df[,c('name','state', 'absnum')]) | 
  duplicated(df[,c('name','state', 'absnum')], fromLast = T)

#            name      state  num   date absnum newcol
# 1 Richard Nixon California -258  day 2    258   TRUE
# 2  Bill Clinton    Indiana  123 day 15    123  FALSE
# 3   George Bush    Florida   42  day 3     42  FALSE
# 4 Richard Nixon California  258 day 45    258   TRUE

Обратите внимание, что строки 1 и 4 помеченыTRUE под newcol, что нормально.А вот новые примеры данных с добавленной сложностью:

name<-c("Richard Nixon", "Bill Clinton", "George Bush", "Richard Nixon", "Bill 
Clinton")
state<-c("California", "Indiana", "Florida", "California", "Indiana")
num<-c("-258", "123", "42", "258", "123")
date<-c("day 2", "day 15", "day 3","day 45", "day 100")
(df<-as.data.frame(cbind(name,state,num, date)))

  name           state      num   date
1 Richard Nixon  California -258  day 2
2 Bill Clinton   Indiana    123   day 15
3 George Bush    Florida    42    day 3
4 Richard Nixon  California 258   day 45
5 Bill Clinton   Indiana    123   day 100

Обратите внимание, что наблюдения 2 и 5 являются частичными дубликатами, но не так, как 1 и 4. Мне нужно применять TRUE только дляте наблюдения, в которых их абсолютные значения совпадают, но НЕ их первоначальные значения.Поэтому я хочу, чтобы результат возвратил следующее:

  name           state      num   date    newcol
1 Richard Nixon  California -258  day 2   TRUE
2 Bill Clinton   Indiana    123   day 15  FALSE
3 George Bush    Florida    42    day 3   FALSE
4 Richard Nixon  California 258   day 45  TRUE
5 Bill Clinton   Indiana    123   day 100 FALSE

Решение, предоставленное предыдущим сообщением SO, применило бы TRUE к строкам 2 и 5, когда я только хотел бы, чтобы это применялось к строкам 1 и 4.

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

В базе R вы можете использовать тот же тест duplicated, что и связанный вопрос о «частичных» дубликатах, но затем исключить значения, которые являются одинаковыми

df$numnum = as.numeric(as.character(df$num))
df$absnum = abs(df$numnum)
df$newcol = (duplicated(df[,c('name','state', 'absnum')]) | 
  duplicated(df[,c('name','state', 'absnum')], fromLast = T)) &
  !(duplicated(df$numnum) | duplicated(df$numnum, fromLast = T))
#            name      state  num    date numnum absnum newcol
# 1 Richard Nixon California -258   day 2   -258    258   TRUE
# 2  Bill Clinton    Indiana  123  day 15    123    123  FALSE
# 3   George Bush    Florida   42   day 3     42     42  FALSE
# 4 Richard Nixon California  258  day 45    258    258   TRUE
# 5  Bill Clinton    Indiana  123 day 100    123    123  FALSE
0 голосов
/ 13 февраля 2019

Один из вариантов заключается в том, чтобы сначала преобразовать тип 'num' в тип numeric, создать еще один столбец с abs абсолютными значениями ('num1'), сгруппированными по 'name', 'state', 'num1', mutate для создания столбца bool путем проверки количества строк, равного 2 (n() == 2), и числа различных sign из 'num', превышающего 1

library(tidyverse)
df %>%
    mutate(num = as.numeric(num), num1 = abs(num)) %>% 
    group_by(name, state, num1) %>% 
    mutate(newcol = n() == 2 & n_distinct(sign(num)) > 1) %>%
    ungroup %>% 
    select(-num1)
# A tibble: 5 x 5
#  name          state        num date    newcol 
#  <chr>         <chr>      <dbl> <chr>   <lgl>
#1 Richard Nixon California  -258 day 2   TRUE 
#2 Bill Clinton  Indiana      123 day 15  FALSE
#3 George Bush   Florida       42 day 3   FALSE
#4 Richard Nixon California   258 day 45  TRUE 
#5 Bill Clinton  Indiana      123 day 100 FALSE

ПРИМЕЧАНИЕ: cbindсоздает matrix и matrix может иметь только один тип.Поэтому, если есть какой-либо символьный столбец или элемент, вся матрица становится character классом.Оборачивая его с помощью data.frame, он распространяется и может преобразовываться в factor (stringsAsFactors = TRUE - по умолчанию) или character (если мы изменим его на FALSE)

data

df <- data.frame(name, state, num, date, stringsAsFactors = FALSE)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...