Эффективно добавлять числовые столбцы и строки с NA и не знать имена кодов

Вот типичный кадр данных:

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".

Ответ 1

Предполагая, что нет имен, я сделал это, чтобы проверить его

names(df)<- NULL

Первый вопрос: Чтобы изменить значения NA для данных на 0, вы можете сделать df [is.na(df)] < -0 (Есть больше решений, но это может сделать, просто поиск здесь в стеке)

df[is.na(df)] <- 0
#    NA    NA NA NA NA
#1 123A Alice 13 13 15
#2 456B  Bobo  8  4  9
#3 789C  Jack 14 16 13
#4 1011  Jill  0  7  6
#5 1213  Zoro 15 12 13

Второй вопрос: вы можете сделать только cbind, чтобы присоединиться к новым данным к последнему столбцу и cbind, чтобы присоединиться к новой строке в конце df. В качестве примера эти данные относятся к среднему значению. Я не уверен, что вам нужно позаботиться о времени, используемом функцией rbind, если это всего лишь менее 100 строк, это неплохо.

vector <- c(14, 7, 14, 4, 13)
df <- cbind(df, vector)
#     1     2  3  4  5 vector  #Note that the name is the name of the vector
#1 123A Alice 13 13 15     14
#2 456B  Bobo  8  4  9      7
#3 789C  Jack 14 16 13     14
#4 1011  Jill  0  7  6      4
#5 1213  Zoro 15 12 13     13

Чтобы изменить имена, которые вы можете сделать names(df)<-names.df, являющиеся именами .df - вектор имен, которые вы хотите получить. Чтобы сделать это, медианы так, вы можете использовать функцию приложения, но я не знаю достаточно хорошо, чтобы показать вам, как...