Как убрать пропущенные значения (NA) при объединении столбцов? - PullRequest
1 голос
/ 27 сентября 2019

Я пытаюсь объединить 5 столбцов в один новый столбец с помощью функции Unite.Тем не менее, все строки содержат много значений NA, создавая переменные, которые выглядят как

Mother|NA|NA|NA|NA
NA|NA|Father|Mother|NA
Mother|Father|NA|Stepmother|NA

Я пытался объединить их, используя этот код:

df2 <- df %>%
unite(Parent_full, Parent:Parent5, sep = "|", remove = TRUE, na.rm = TRUE) 

Но это дает мне следующееошибка: ошибка: TRUE должен соответствовать позициям или именам столбцов, а не логическому вектору

Я также посмотрел на форуме и обнаружил, что, возможно, функция unite na.rm не активна?

Вот некоторые данные для воссоздания моего набора данных

Name <- c('Paul', 'Edward', 'Mary')
Postalcode <- c('4732', '9045', '3476')
Parent <- c('Mother', 'NA', 'Mother')
Parent2 <- c('NA', 'NA', 'Father')
Parent3 <- c('NA', 'Father', 'NA')
Parent4 <- c('NA', 'Mother', 'Stepmother')
Parent5 <- c('NA', 'NA', 'NA')

df <- data.frame(Name, Postalcode, Parent, Parent2, Parent3, Parent4, Parent5)

Хотелось бы узнать, как объединить мои столбцы без NA.

ОБНОВЛЕНИЕ:

IСейчас я обновил пакет tidyr, и я добавил «na = c (», «NA») »в свою команду read_csv.

Теперь команда

df2 <- df %>%
unite(Parent_full, Parent:Parent5, sep = "|", remove = TRUE, na.rm = TRUE) 

работает, однако дляПо некоторым причинам, NA в конце значения остается.Теперь мои столбцы выглядят так:

Mother|NA
Father|Mother|NA
Mother|Father|Stepmother|NA
Does anyone know what went wrong now?

Ответы [ 3 ]

3 голосов
/ 27 сентября 2019

У вас есть пара проблем,

1) NA не являются действительными NA (проверка is.na(df$Parent2))

2) Ваши столбцы являются факторами

При построении фрейма данных используйте stringsAsFactors = FALSE

df <- data.frame(Name, Postalcode, Parent, Parent2, Parent3, Parent4, 
                 Parent5, stringsAsFactors = FALSE)

, а затем замените NA и используйте unite

library(dplyr)
df %>%
  na_if('NA') %>%
  tidyr::unite(Parent_full, Parent:Parent5, sep = "|", na.rm = TRUE)

#    Name Postalcode              Parent_full
#1   Paul       4732                   Mother
#2 Edward       9045            Father|Mother
#3   Mary       3476 Mother|Father|Stepmother

Если данные уже загружены, мыможете изменить их, используя mutate_if

df %>%  
 mutate_if(is.factor, as.character) %>%
 na_if('NA') %>%
 tidyr::unite(Parent_full, Parent:Parent5, sep = "|", na.rm = TRUE)
2 голосов
/ 27 сентября 2019

Ваша главная проблема в том, что вы еще не обновились до tidyr 1.0.Это сообщение об ошибке - лучшее, что предыдущая версия может сделать с помощью ввода na.rm = TRUE, поскольку этот аргумент не существовал ранее.Он думает, что вы даете ему именованный аргумент как часть ....

В частности, просто запустите install.packages("tidyr"), и оно должно работать.Возможно, вам придется сначала перезапустить R, поэтому tidyr в данный момент не загружается.

Если ваши пропущенные значения представляют собой "NA" строки, то, как указал Ронак, вам нужно использовать na_if() для нихпервый.Это странно для меня, потому что ваш исходный фрагмент кода делает его похожим на настоящие NA из-за красной подсветки.Но тогда ваш код представления имеет 'NA' значения, которые определенно будут строками.В любом случае, вы говорите, что читаете из CSV, поэтому было бы чище и быстрее запустить код для чтения CSV, чтобы правильно читать NA с аргументом na или подобным.

Ответ на редактирование: Это похоже на ошибку, из-за того, что NA в конце объединенной строки не удаляются должным образом.Ну, во всяком случае, исправить это легко, и, вероятно, лучше, чем все остальное, что мы могли бы сделать:

df2 <- df %>%
  unite(Parent_full, Parent:Parent5, sep = "|", na.rm = TRUE) %>%
  mutate_at("Parent_full", . %>%
              str_remove("(^|\\|)NA$") %>%
              na_if(""))

Это гарантирует две вещи: 1) что буквы «NA» в конце строки удаляются толькоесли они там из-за unite(), с трубкой (если что-нибудь) перед ними;и 2) если здесь нет пропущенных значений в строке, тогда значение будет правильным NA, а не "NA", "" или чем-то еще, что, как я полагаю, является тем, что вы хотите.

Обновление : Я обнаружил, что ошибка относится к любому столбцу, который не содержит ничего, кроме NA, то есть na.rm = TRUE удаляет только NA из столбцов, которые имеют хотя бы одно не пропущенное значение.Я подал отчет об ошибке: https://github.com/tidyverse/tidyr/issues/765

Учитывая это, тем не менее, оптимальное решение, вероятно, состоит в том, чтобы просто удалить все столбцы, которые все являются NA заранее.Однако, если это производственный код, то он становится действительно сложным, поскольку вы должны указать unite(), чтобы не нарушать, если какой-либо или даже все столбцы, которые нужно объединить, будут отброшены этим предыдущим шагом.

Обновление 2 : Как указывалось в ответе на сообщение об ошибке, проблема в том, что этот пропущенный столбец является логическим.Таким образом, это делает оптимальное решение: прочитайте в таких столбцах как символ или приведите их к символу перед объединением.Полное представление для этого:

library(tidyverse)

Name <- c('Paul', 'Edward', 'Mary')
Postalcode <- c('4732', '9045', '3476')
Parent <- c('Mother', NA, 'Mother')
Parent2 <- c(NA, NA, 'Father')
Parent3 <- c(NA, 'Father', NA)
Parent4 <- c(NA, 'Mother', 'Stepmother')
Parent5 <- c(NA, NA, NA)

(df <- data.frame(Name, Postalcode, Parent, Parent2, Parent3, Parent4, Parent5))
#>     Name Postalcode Parent Parent2 Parent3    Parent4 Parent5
#> 1   Paul       4732 Mother    <NA>    <NA>       <NA>      NA
#> 2 Edward       9045   <NA>    <NA>  Father     Mother      NA
#> 3   Mary       3476 Mother  Father    <NA> Stepmother      NA

(df2 <- df %>%
    mutate_at(vars(Parent:Parent5), as.character) %>% 
    unite(Parent_full, Parent:Parent5, sep = "|", na.rm = TRUE))
#>     Name Postalcode              Parent_full
#> 1   Paul       4732                   Mother
#> 2 Edward       9045            Father|Mother
#> 3   Mary       3476 Mother|Father|Stepmother

Создано в 2019-09-27 пакетом представить (v0.3.0)

0 голосов
/ 27 сентября 2019

Позже вы можете удалить NA следующим образом:

df %>%
  unite(Parent_full, Parent:Parent5, sep = "|", remove = TRUE) %>% 
  mutate(Parent_full = gsub("(?<![a-zA-Z])NA\\||\\|NA(?![a-zA-Z])|\\|NA$", '', Parent_full, perl = T))
    Name Postalcode              Parent_full
1   Paul       4732                   Mother
2 Edward       9045            Father|Mother
3   Mary       3476 Mother|Father|Stepmother

Он заменяет NA| без предшествующей буквы или |NA, за которым не следует буква или |NA наконец строки с пустой строкой

...