удаление строк на основе двух условий из таблицы данных в R - PullRequest
0 голосов
/ 11 апреля 2020

У меня есть data.table с кодом страны и соответствующим названием страны. В некоторых случаях страна не известна, и "OTHER" используется для указания неизвестного кода. Мои данные противоречивы, поскольку для некоторых code у меня есть имя country, но также есть строка с "OTHER",, например IRLAND или LUXEMBURG.

code <- c(104, 105, 105, 106, 109, 112, 115, 115)
country <- c("GERMANY", "IRLAND", "OTHER", "FRANCE", "FRANCE", "ITALY",  "OTHER", "LUXEMBURG")
id_country <- cbind(code, country)
id_country <- as.data.table(id_country)

Что я хочу сделать: я хочу получить уникальный code - для каждого кода будет только одна строка, в идеале с названием страны, если она недоступна, тогда с помощью «ДРУГОЙ». Я ищу самое простое решение.

Пока я думал сначала проверить, есть ли в моем data.table некоторые из этих несоответствий. Если да, то удалите все строки, в которых есть и название страны, и «ДРУГОЕ» в столбце country. Я пробовал следующее, но ни один из duplicates не удаляется

if (length(unique(id_country$code)) != length(unique(id_country))){

  # replace "OTHER" with the corresponding country name 
  duplicates <- id_country[duplicated(code),]
  id_country <- id_country[!(id_country$code %in% duplicates & id_country$country == "OTHER"),]

}

желаемый вывод:

code <- c(104, 105, 106, 109, 112, 115)
country <- c("GERMANY", "IRLAND", "FRANCE", "FRANCE", "ITALY", "LUXEMBURG")
id_country <- cbind(code, country)
id_country <- as.data.table(id_country)

Ответы [ 4 ]

1 голос
/ 11 апреля 2020

Вот еще один вариант, если вы хотите использовать dplyr:

code_n подсчитывает количество повторов в code и ifelse условно заполняет переменную country при замене любых «ДРУГИХ» записей на NaN для дубликата code. Записи NaN позже отфильтровываются. Код также работает, если для уникального кода есть одна запись с «ДРУГОЙ» в качестве фильтрации страны! = «ДРУГОЙ» не будет работать в этом случае.

id_country %>% group_by (code) %>% mutate(code_n=n()) %>% mutate(country = ifelse(code_n == 1,country,ifelse(country!="OTHER",country,NaN))) %>% filter(country!=NaN) %>% select(-code_n)

Вывод

Тибль: 6 х 2

# Groups:   code [6]
  code  country  
  <chr> <chr>    
1 104   GERMANY  
2 105   IRLAND   
3 106   FRANCE   
4 109   FRANCE   
5 112   ITALY    
6 115   LUXEMBURG
0 голосов
/ 11 апреля 2020

Если необходимо удалить элементы, которые имеют OTHER, а все элементы, отмеченные OTHER, являются дубликатами названия другой страны, мы можем просто выбрать строки, в которых страна не равна OTHER.

library(data.table)
code <- c(104, 105, 105, 106, 109, 112, 115, 115)
country <- c("GERMANY", "IRLAND", "OTHER", "FRANCE", "FRANCE", "ITALY",  "OTHER", "LUXEMBURG")
id_country <- cbind(code, country)
id_country <- as.data.table(id_country)

id_country[country != "OTHER",]

Если в списке есть «действительные» неизвестные страны (т. Е. Не дублирующийся код страны с именем OTHER, решение немного сложнее.

Сначала мы найдем дублированные страны после изменения входных данных с действительной OTHER, страна 117.

library(data.table)
code <- c(104, 105, 105, 106, 109, 112, 115, 115,117)
country <- c("GERMANY", "IRLAND", "OTHER", "FRANCE", "FRANCE", "ITALY",  "OTHER", 
             "LUXEMBURG","OTHER")
id_country <- cbind(code, country)
id_country <- as.data.table(id_country)
dupCodes <- id_country[, 'count' := .N, by = code][count > 1,.SD[1],by = code][[1]]

Тогда мы будем удалять только те строки, где country равно OTHER и там являются дубликатами code.

id_country[country != "OTHER" | !(code %in% dupCodes),]

... и вывода:

> id_country[country != "OTHER" | !(code %in% dupCodes),]
   code   country
1:  104   GERMANY
2:  105    IRLAND
3:  106    FRANCE
4:  109    FRANCE
5:  112     ITALY
6:  115 LUXEMBURG
7:  117     OTHER
> 

Исправление исходной ошибки кодирования

Как изначально написано, код в сообщение с вопросом содержит небольшую ошибку, из-за которой всегда завершается последняя операция поднабора.

 duplicates <- id_country[duplicated(code),]

Поскольку duplicates является вектором data.table, а не цифрой c, следующий фрагмент кода всегда оценивает в FALSE.

id_country$code %in% duplicates

Тот факт, что этот код находится внутри блока if(), затрудняет понимание того, что duplicates является таблицей данных, поскольку мы не можем видеть ее в средстве просмотра среды RStudio. Если я запускаю блок кода вне блока if(), Осмотрев объект, я вижу следующее.

enter image description here

Очевидно, duplicates не является вектором.

Эта проблема приводит к тому, что оставшаяся часть операции поднабора возвращает каждую строку из таблицы входных данных.

id_country <- id_country[!(id_country$code %in% duplicates & id_country$country == "OTHER"),]

Почему?

id_country$code %in% duplicates
> id_country$code %in% duplicates
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
>

Мы можем исправить дефект, возвращая вектор вместо таблицы данных из строки кода, которая делает присвоение duplicates, следующим образом.

if (length(unique(id_country$code)) != length(unique(id_country))){

     # extract first column of resulting data.table as a vector
     duplicates <- id_country[duplicated(code),][[1]]
     # subset out duplicate rows named OTHER
     id_country <- id_country[!(id_country$code %in% duplicates & id_country$country == "OTHER"),]

}
id_country

... и вывод:

> id_country
   code   country
1:  104   GERMANY
2:  105    IRLAND
3:  106    FRANCE
4:  109    FRANCE
5:  112     ITALY
6:  115 LUXEMBURG
> 
0 голосов
/ 11 апреля 2020

Мы можем проверить состояние с if:

library(data.table)

id_country[, .(country = if(any(country != 'OTHER')) 
                        country[country != 'OTHER'][1L] else 'OTHER'), code]

#   code   country
#1:  104   GERMANY
#2:  105    IRLAND
#3:  106    FRANCE
#4:  109    FRANCE
#5:  112     ITALY
#6:  115 LUXEMBURG
0 голосов
/ 11 апреля 2020

Я имею в виду два решения. Оба они дадут одинаковый результат. Второй может быть более подходящим, если у вас есть объемные данные, потому что он избегает слияния.

В вашем примере не было наблюдения, где только один код связан с OTHER. Этот вид наблюдений не будет изменен обоими методами.

Решение 1

Первый основан на merge. Идея состоит в том, чтобы очистить data.table, который содержит только код, а затем объединить с начальными данными

# METHODE 1: MERGE
id_country2 <- id_country[,.('clean_code' = unique(country)), by = code]
id_country2[, 'number_codes' := .N, by = code]
id_country2 <- id_country2[!(number_codes == 2 & clean_code == "OTHER")]

merge(id_country, id_country2)

   code number_codes   country clean_code
1:  104            1   GERMANY    GERMANY
2:  105            2    IRLAND     IRLAND
3:  105            2     OTHER     IRLAND
4:  106            1    FRANCE     FRANCE
5:  109            1    FRANCE     FRANCE
6:  112            1     ITALY      ITALY
7:  115            2     OTHER  LUXEMBURG
8:  115            2 LUXEMBURG  LUXEMBURG

Решение 2

Во втором решении используется условная замена непосредственно в исходном кадре данных , Идея состоит в том, чтобы создать функцию до того, как она выполнит подстановку, а затем применить ее только к некоторым кодам.

Функция:

replace_country <- function(x){
  val <- unique(x)
  return(
     gsub(pattern = "OTHER", replacement = val[val != "OTHER"][1],
          x)
) 
}

Возможно, есть более элегантный способ определить ее, но она сделаю работу. Кстати, я поставил val[val != "OTHER"][1], чтобы вы заменили только одно значение. Это может быть дополнительной осторожностью, но на всякий случай.

Эта функция будет вызываться с использованием lapply + SD глаголов

id_country[, 'number_codes' := uniqueN(country), by = "code"]
id_country[number_codes > 1,  country := lapply(.SD, replace_country), .SDcols = "country",
           by = "code"]


  code   country number_codes
1:  104   GERMANY            1
2:  105    IRLAND            2
3:  105    IRLAND            2
4:  106    FRANCE            1
5:  109    FRANCE            1
6:  112     ITALY            1
7:  115 LUXEMBURG            2
8:  115 LUXEMBURG            2

Функция replace_country применяется только к наблюдениям с number_codes> 1 с этим синтаксисом. Ваш фрейм данных напрямую обновляется по ссылке

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