apply () дает значения NA для каждого столбца - PullRequest
5 голосов
/ 15 марта 2012

У меня недавно была странная проблема с apply.Рассмотрим следующий пример:

set.seed(42)
df <- data.frame(cars, foo = sample(LETTERS[1:5], size = nrow(cars), replace = TRUE))
head(df)
  speed dist foo
1     4    2   E
2     4   10   E
3     7    4   B
4     7   22   E
5     8   16   D
6     9   10   C

Я хочу использовать apply, чтобы применить функцию fun (скажем, mean) к каждому столбцу этого data.frame.Если data.frame содержит только numeric значений, у меня нет проблем:

apply(cars, 2, mean)
speed  dist 
15.40 42.98 

Но при попытке с моими data.frame, содержащими numeric и character данные, кажется,fail:

apply(df, 2, mean)
speed  dist   foo 
   NA    NA    NA 
Warning messages:
1: In mean.default(newX[, i], ...) :
  argument is not numeric or logical: returning NA
2: In mean.default(newX[, i], ..) :
  argument is not numeric or logical: returning NA                 
3: In mean.default(newX[, i], ...) :                              
  argument is not numeric or logical: returning NA

Конечно, я ожидал получить NA для столбца character, но я все равно хотел бы получить значения для столбцов numeric.

sapply(df, class)
    speed      dist       foo 
"numeric" "numeric"  "factor" 

Любые указатели будут оценены, так как я чувствую, что упускаю что-то очень очевидное здесь!

Ответы [ 3 ]

10 голосов
/ 15 марта 2012

В первом предложении описания для ?apply написано:

Если X не массив, а объект класса с ненулевым dim значение (например, фрейм данных), применить попытки привести его к массиву через as.matrix, если он двумерный (например, фрейм данных) или через as.array.

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

Полагаю, я должен вам описание альтернативы, так что вот, пожалуйста. фреймы данных - это просто списки, поэтому, если вы хотите применить функцию к каждому столбцу, используйте lapply или sapply.

3 голосов
/ 15 марта 2012

apply работает с матрицей, и матрица должна быть одного типа.Таким образом, df преобразуется в матрицу, и поскольку он содержит символ, все столбцы становятся символами.

> apply(df, 2, class)
      speed        dist         foo 
"character" "character" "character" 

Чтобы получить то, что вы хотите, посмотрите colwise и numcolwiseфункции в plyr.

> numcolwise(mean)(df)
  speed  dist
1  15.4 42.98
2 голосов
/ 15 марта 2012

Вы применяете функцию к столбцам data.frame.Поскольку data.frame является списком, вы можете использовать lapply или sapply вместо apply:

sapply(df, mean)

speed  dist   foo 
15.40 42.98    NA 
Warning message:
In mean.default(X[[3L]], ...) :
  argument is not numeric or logical: returning NA

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

sapply(df, function(x)ifelse(is.numeric(x), mean(x), NA))

speed  dist   foo 
15.40 42.98    NA 
...