Удаление пар аддитивных инверсий - PullRequest
0 голосов
/ 13 февраля 2019

Этот вопрос основан на двух предыдущих вопросах, которые я задавал для SO, каждый более сложный, чем предыдущий.В предыдущем посте - Как идентифицировать зеркальные дубликаты строк в R -

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

name<-c("Richard Nixon", "Bill Clinton", "George Bush", "Richard Nixon", "Bill Clinton", "Richard Nixon", "Abe Lincoln","Richard Nixon", "Bill Clinton", "Richard Nixon")
state<-c("California", "Indiana", "Florida", "California", "Indiana", "California","Oregon","California", "Indiana", "California")
num<-c("-258", "123", "42", "258", "123", "-258", "87","258", "-123", "258")
date<-c("day 9", "day 2", "day 15", "day 3","day 45", "day 100", "day 99", "day 10", "day 11", "day 100")

(df <- data.frame(name, state, num, date, stringsAsFactors = FALSE))
            name      state  num    date
1  Richard Nixon California -258   day 9
2   Bill Clinton    Indiana  123   day 2
3    George Bush    Florida   42  day 15
4  Richard Nixon California  258   day 3
5   Bill Clinton    Indiana  123  day 45
6  Richard Nixon California -258 day 100
7    Abe Lincoln     Oregon   87  day 99
8  Richard Nixon California  258  day 10
9   Bill Clinton    Indiana -123  day 11
10 Richard Nixon California  258 day 100

Если бы я запустил отличное решение из предыдущего поставленного мной SO вопроса, это привело бы к следующему

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

.проблема с вышеприведенным выводом состоит в том, что для Ричарда Никсона и для Билла Клинтона есть одна строка, слишком много, где появляется ИСТИНА.Мой желаемый вывод следующий:

   name          state        num date    newcol
 1 Abe Lincoln   Oregon        87 day 99  FALSE 
 2 Bill Clinton  Indiana      123 day 2   TRUE
 3 Bill Clinton  Indiana      123 day 45  FALSE
 4 Bill Clinton  Indiana     -123 day 11  TRUE  
 5 George Bush   Florida       42 day 15  FALSE 
 6 Richard Nixon California  -258 day 9   TRUE  
 7 Richard Nixon California   258 day 3   TRUE  
 8 Richard Nixon California  -258 day 100 TRUE  
 9 Richard Nixon California   258 day 10  TRUE  
10 Richard Nixon California   258 day 100 FALSE

Обратите внимание, что только строки, зеркально совпадающие с зеркальным совпадением, совпадают в том смысле, что строки являются дубликатами, за исключением того, что они являются аддитивными инверсиями друг друга для столбца num.Таким образом, я в основном пытаюсь идентифицировать все строки, которые совпадают вдоль переменных name и state и являются аддитивными инверсиями друг друга вдоль переменной num, с условием, что аддитивные инверсии будут уникальными - уникальными в том смысле, что num следует считать только аддитивной инверсией не более одной строки.

Для дополнительной ясности, если вышеприведенное объяснение нуждается в разъяснении, в противном случае пропустите:

Таким образом, некоторый процесс, который проходит по каждой строке, идентифицируя первую строку, которая соответствует критериям того, чтобы быть частичнымmatch (частичное в смысле абсолютного значения / аддитивного обратного), а затем присваивает TRUE эти две строки, а затем переходит к следующему наблюдению и так далее.Например, код может начинаться с Abe Lincoln и проходить через каждую последующую строку, пока не будет найдена частично совпадающая строка, если строка не найдена, то в столбце newcol FALSE указано значение, которое должно быть сгенерировано.Затем он переходит к Биллу Клинтону, штат Индиана, 123 и проходит по строкам, чтобы определить частичное совпадение.Следующая строка НЕ ​​является частичным совпадением, поскольку 123 и 123 не являются частичными совпадениями (они являются полными совпадениями), но следующая строка является частичным совпадением (123 и -123), в результате чего генерируется значение TRUEдля newcol для этого наблюдения, а также для частично подобранного ряда.Затем он идет в третий ряд (Билл Клинтон, Индиана, 123).Важной частью этого шага является то, что если строка уже имеет значение для newcol, цикл не должен проходить через нее.Таким образом, для этой строки (третьей строки) цикл пропустил бы первую строку (с Абэ Линкольном) b / c, которая уже имеет значение FALSE, и пропустил бы вторую строку и 4-ую строку bc, эти два уже были сопоставленывместе, в результате чего FALSE для третьей строки b / c, оставшиеся строки не были частично сопоставлены, а единственное частичное совпадение во фрейме данных уже сопоставлено с другой инверсией.

Ответы [ 2 ]

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

Возможно, нам потребуется выполнить вторую группировку с sign, чтобы создать другую группу последовательности, которая поможет идентифицировать те строки, у которых нет совпадающей пары, и обновить их до FALSE

library(dplyr)
df %>%
     mutate(num = as.numeric(num), num1 = abs(num)) %>% 
     group_by(name, state, num1) %>% 
     mutate(newcol = n() > 1 & n_distinct(sign(num)) > 1) %>% 
     group_by(grp = sign(num), add = TRUE) %>% 
     mutate(rn = row_number()) %>% 
     group_by(name, state, num1, rn) %>% 
     mutate(newcol = replace(newcol, n()==1, FALSE)) %>%
     ungroup %>%
     select(-grp, -num1, -rn) %>% 
     arrange(name)
#A tibble: 10 x 5
#   name          state        num date    newcol
#   <chr>         <chr>      <dbl> <chr>   <lgl> 
# 1 Abe Lincoln   Oregon        87 day 99  FALSE 
# 2 Bill Clinton  Indiana      123 day 2   TRUE  
# 3 Bill Clinton  Indiana      123 day 45  FALSE 
# 4 Bill Clinton  Indiana     -123 day 11  TRUE  
# 5 George Bush   Florida       42 day 15  FALSE 
# 6 Richard Nixon California  -258 day 9   TRUE  
# 7 Richard Nixon California   258 day 3   TRUE  
# 8 Richard Nixon California  -258 day 100 TRUE  
# 9 Richard Nixon California   258 day 10  TRUE  
#10 Richard Nixon California   258 day 100 FALSE 
0 голосов
/ 13 февраля 2019

Вот простое рабочее решение, которое масштабируется до случая, когда у вас есть более 1 дополнительного наблюдения без зеркала.Основная идея очень проста: сгруппируйте, определите количество положительных и отрицательных значений, упорядочите наблюдения так, чтобы отрицательные значения продолжались положительными, определите, являются ли отрицательные или положительные значения избыточными, а затем сгенерируйте вектор ИСТИНА / ЛОЖЬ.Поскольку наблюдения упорядочены от отрицательного до положительного, просто сформулировать, как должен выглядеть вектор исхода для случаев, когда отрицательные значения не сопоставлены или положительные случаи не сопоставлены.

Код ниже:

# Load data and libraries
library(dplyr)
name<-c("Richard Nixon", "Bill Clinton", "George Bush", "Richard Nixon", "Bill Clinton", "Richard Nixon", "Abe Lincoln","Richard Nixon", "Bill Clinton", "Richard Nixon")
state<-c("California", "Indiana", "Florida", "California", "Indiana", "California","Oregon","California", "Indiana", "California")
num<-c("-258", "123", "42", "258", "123", "-258", "87","258", "-123", "258")
date<-c("day 9", "day 2", "day 15", "day 3","day 45", "day 100", "day 99", "day 10", "day 11", "day 100")

# create dataframe
df <- data.frame(name, state, num, date, stringsAsFactors = FALSE)

df %>% 
  mutate(num = as.numeric(num), # to work with
              row = row_number() # for reordering
         ) %>%
  group_by(name, state) %>% 
  arrange(num) %>% # we order the observations so that all the negs
                   # proceed the pos. 
  mutate(negs = max(0, table(sign(num))["-1"], na.rm=T), # get the number of negatives
         pos = max(0, table(sign(num))["1"], na.rm=T), # get the number of positives
         newcol = ifelse(negs > pos, # See which is in excess
                         c(rep(FALSE, negs[1]-pos[1]), rep(TRUE, 2*pos[1])),
                         c(rep(TRUE, 2*negs[1]), rep(FALSE, pos[1]-negs[1])))
         ) %>%
  arrange(name, row) %>%
  dplyr::select(-negs, -pos, -row)
#> # A tibble: 10 x 5
#> # Groups:   name, state [4]
#>    name          state        num date    newcol
#>    <chr>         <chr>      <dbl> <chr>   <lgl> 
#>  1 Abe Lincoln   Oregon        87 day 99  FALSE 
#>  2 Bill Clinton  Indiana      123 day 2   TRUE  
#>  3 Bill Clinton  Indiana      123 day 45  FALSE 
#>  4 Bill Clinton  Indiana     -123 day 11  TRUE  
#>  5 George Bush   Florida       42 day 15  FALSE 
#>  6 Richard Nixon California  -258 day 9   TRUE  
#>  7 Richard Nixon California   258 day 3   TRUE  
#>  8 Richard Nixon California  -258 day 100 TRUE  
#>  9 Richard Nixon California   258 day 10  TRUE  
#> 10 Richard Nixon California   258 day 100 FALSE

Создано в 2019-02-13 пакетом Представления (v0.2.1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...