Вот типичный кадр данных:
df <- data.frame(
'ID' = c("123A","456B","789C","1011","1213")
, 'Name' = c("Alice","Bobo","Jack","Jill","Zoro")
, 'Quizzes' = c(13,8,14,NA,15)
, 'Midterm' = c(13,4,16,7,12)
, 'Final' = c(15,9,13,6,13)
)
df
ID Name Quizzes Midterm Final
1 123A Alice 13 13 15
2 456B Bobo 8 4 9
3 789C Jack 14 16 13
4 1011 Jill NA 7 6
5 1213 Zoro 15 12 13
Я хотел бы добавить числовые столбцы (исключая 'ID'
и 'Name'
) для вычисления столбца 'Grade'
. Затем я хотел бы вычислить среднее, среднее, максимальное, минимальное и стандартное отклонение для каждого из этих числовых столбцов. И, наконец, я хотел бы объединить статистику в исходный фрейм данных.
Одна из проблем заключается в том, что имена столбцов (ID
, Name
, Quizzes
, Midterm
, Final
в этом примере) неизвестны. Количество столбцов также неизвестно, оно может содержать 2 идентификационных столбца (ID
, Name
в этом примере) или более и может содержать 3 класса (Quizzes
, Midterm
, Final
в этом примере) или более.
Однако я знаю, что первый столбец всегда содержит уникальный идентификатор.
Может отсутствовать данные и/или данные NA.
При добавлении по столбцу (добавление по горизонтали), я хотел бы предположить, что недостающие и NA обрабатываются как ноль. При добавлении (или вычислении любой другой статистики) по строке (добавление по вертикали) я бы хотел проигнорировать недостающие и значения NA (рассматривать их как выбросы).
Мои трудности делятся на 2 категории: 1) работа с NA и отсутствующими значениями; 2) слияние кадров данных, когда имена команд неизвестны.
df$Means = rowMeans(df[sapply(df, is.numeric)])
df
ID Name Quizzes Midterm Final Means
1 123A Alice 13 13 15 13.66667
2 456B Bobo 8 4 9 7.00000
3 789C Jack 14 16 13 14.33333
4 1011 Jill NA 7 6 NA
5 1213 Zoro 15 12 13 13.33333
Я знаю, как удалить NA:
df$Means = rowMeans(df[sapply(df, is.numeric)], na.rm = TRUE)
df
ID Name Quizzes Midterm Final Means
1 123A Alice 13 13 15 13.66667
2 456B Bobo 8 4 9 7.00000
3 789C Jack 14 16 13 14.33333
4 1011 Jill NA 7 6 6.50000
5 1213 Zoro 15 12 13 13.33333
но я хотел бы вместо этого рассматривать их как нули.
Первый вопрос: Есть ли один-лайнер для обработки NA как нуль (0) без чередования кадра данных?
Изменить 1: Позвольте мне пояснить, что я знаю, как заменить NA с 0 в фрейме данных с помощью df[is.na(df)] <-0
, но я хочу сохранить исходные данные фрейма данных без изменений, сохраняя NA, в то время как вычислительные средства с NA, обрабатываются как ноль.
Немного объяснения: sapply(df, is.numeric)
предназначен для игнорирования первых двух столбцов, имена кодов которых я не знаю.
Я также хотел бы объединить статистику в исходный фреймворк для удобства отображения и экспорта на рабочий лист. Я получил часть пути, но не очень далеко. Я попытался адаптировать описанное здесь решение Добавить новую строку в dataframe, в конкретный индекс строки, а не прилагается?
# create a dataframe of sums
data.frame(ID="Mean",t(colMeans(df[sapply(df, is.numeric)], na.rm = TRUE)))
ID Quizzes Midterm Final
1 Mean 12.5 10.4 11.2
# add sums to original data frame
newRow <- data.frame(ID="Mean",t(colMeans(df[sapply(df, is.numeric)], na.rm = TRUE)))
insertRow <- function(df, r, p) {
# df = data frame
# r = new row
# p = position
df[seq(p+1,nrow(df)+1),] <- df[seq(p,nrow(df)),]
df[p,] <- r
df
}
insertRow(df[,-1],newRow,nrow(df)+1)
Name Quizzes Midterm Final
1 Alice 13.0 13.0 15.0
2 Bobo 8.0 4.0 9.0
3 Jack 14.0 16.0 13.0
4 Jill NA 7.0 6.0
5 Zoro 15.0 12.0 13.0
NA <NA> 12.5 10.4 11.2
7 <NA> NA NA NA
Warning message:
In `[<-.factor`(`*tmp*`, iseq, value = 1L) :
invalid factor level, NA generated
Второй вопрос: Как эффективно объединить мои вертикальные суммы (и средства и медианы и т.д.) обратно в исходный фрейм данных? Напомним, что я не знаю имена кодов, я знаю только, что первый столбец является уникальным идентификатором. Изменить: Решение описано ниже.
Изменить 2: Я избегал использования rbind, потому что ищу эффективное решение . URL Добавить новую строку в dataframe, в определенном индексе строк, а не прилагаемом? утверждает, что "Здесь решение, которое позволяет избежать (часто медленного) вызова rbind". Я не знаю, почему rbind может быть медленным, но я последовал совету в попытке реализовать решение, данное там, к моей настоящей проблеме.
Спасибо! и, пожалуйста, просите уточнить, если это необходимо.
Изменить 3:
Поток, который я привел выше, Добавить новую строку в dataframe, в определенном индексе строк, а не при добавлении?, фактически имел "эффективное" решение проблемы, которая избегает странного поведения, описанного выше с функцией insertRow (я спешу добавить, что странное поведение, скорее всего, является результатом неправильного использования этой функции). Вот функция, которая работает и решает мой второй вопрос:
insertRow2 <- function(df, r, p) {
df <- rbind(df,r)
df <- df[order(c(1:(nrow(df)-1),p-0.5)),]
row.names(df) <- 1:nrow(df)
return(df)
}
insertRow2(df[,-1],newRow,nrow(df)+1)
Name Quizzes Midterm Final
1 Alice 13.0 13.0 15.0
2 Bobo 8.0 4.0 9.0
3 Jack 14.0 16.0 13.0
4 Jill NA 7.0 6.0
5 Zoro 15.0 12.0 13.0
6 Mean 12.5 10.4 11.2
Что касается моего первого вопроса, так как не было ни одного лайнера, я создал пользовательские функции следующим образом:
colMeanz <- function(df) {
df[is.na(df)] <- 0
return(colMeans(df))
}
Скорее неэлегантный, но там вы идете. Спасибо Llopis за помощь в этом.
Дополнительное объяснение контекста: при вычислении одного студента имеет смысл рассматривать NA как ноль, а при вычислении всего класса означает, что имеет смысл рассматривать NA с помощью "na.rm = TRUE".