Проблема с пользовательской функцией в R - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь изменить тип данных моих переменных во фрейме данных на «фактор», если они «символьные». Я попытался воспроизвести проблему, используя пример данных, как показано ниже

a <- c("AB","BC","AB","BC","AB","BC")
b <- c(12,23,34,45,54,65)
df <- data.frame(a,b)
str(df)

'data.frame':   6 obs. of  2 variables:
 $ a: chr  "AB" "BC" "AB" "BC" ...
 $ b: num  12 23 34 45 54 65

Я написал следующую функцию, чтобы добиться этого

abc <- function(x) {
  for(i in names(x)){
    if(is.character(x[[i]])) {
      x[[i]] <- as.factor(x[[i]])
    }
  }
}

Функция выполняется правильно, если я передаю фрейм данных (df), но все равно она не меняет «символ» на «фактор».

abc(df)

str(df)
'data.frame':   6 obs. of  2 variables:
 $ a: chr  "AB" "BC" "AB" "BC" ...
 $ b: num  12 23 34 45 54 65

ПРИМЕЧАНИЕ: прекрасно работает с циклом for и if условии. Когда я попытался обобщить его, написав вокруг него функцию, возникла проблема.

Пожалуйста, помогите. Чего мне не хватает?

1 Ответ

0 голосов
/ 06 сентября 2018

Помимо комментария от @Roland, вы должны использовать прекрасные возможности индексации R и узнать о семействе *apply. С этим вы можете переписать свой код в

change_to_factor <- function(df_in) {
    chr_ind <- vapply(df_in, is.character, logical(1))
    df_in[, chr_ind] <- lapply(df_in[, chr_ind, drop = FALSE], as.factor)
    df_in
}

Объяснение

  • vapply перебирает все элементы списка, применяет функцию к каждому элементу и возвращает значение заданного типа (здесь логическое значение logical(1)). Поскольку в R фреймы данных на самом деле lists, где каждый (список) элемент должен иметь одинаковую длину, вы можете удобно зацикливаться на всех столбцах фрейма данных и применять функцию is.character к каждому столбцу , vapply затем возвращает логический (логический) вектор со значениями TRUE/FALSE в зависимости от того, был ли столбец символьным или нет.
  • Затем вы можете использовать этот логический вектор для поднабора вашего фрейма данных, чтобы просматривать только столбцы, которые являются символьными столбцами.
  • lapply - еще один член семейства *apply, который просматривает элементы списка и возвращает список. Теперь мы зациклились на символьных столбцах, применили к ним as.factor и вернули их список, который удобно хранить в исходных позициях в кадре данных

Кстати, если вы посмотрите на str(df), вы увидите, что столбец b уже является фактором. Это потому, что data.frame автоматически преобразует символьные столбцы в символы. Чтобы избежать этого, вам нужно передать stringsAsFactors = FALSE на data.frame:

a <- c("AB", "BC", "AB", "BC", "AB", "BC")
b <- c(12, 23, 34, 45, 54, 65)
df <- data.frame(a, b)

str(df) # column b is factor
# 'data.frame':   6 obs. of  2 variables:
# $ a: Factor w/ 2 levels "AB","BC": 1 2 1 2 1 2
# $ b: num  12 23 34 45 54 65

str(df2 <- data.frame(a, b, stringsAsFactors = FALSE))
# 'data.frame':   6 obs. of  2 variables:
#  $ a: chr  "AB" "BC" "AB" "BC" ...
#  $ b: num  12 23 34 45 54 65

str(change_to_factor(df2))
# 'data.frame':   6 obs. of  2 variables:
#  $ a: Factor w/ 2 levels "AB","BC": 1 2 1 2 1 2
#  $ b: num  12 23 34 45 54 65

Возможно, стоит изучить синтаксис tidyverse, с которым вы можете просто

library(tidyverse)
df2 %>% 
  mutate_if(is.character, as.factor) %>% 
  str()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...