Выявление выбросов в данных R по уровням факторов и столбцам - PullRequest
0 голосов
/ 14 мая 2019

У меня есть регулярно обновляемая биологическая база данных, в настоящее время содержащая записи 13 500 особей по 250 видам (виды = уровни факторов в 1-й колонке). Каждый человек имеет уникальный идентификатор (2-й столбец). Для каждого человека было зарегистрировано 7 различных измерений (столбцы 3-9). С таким количеством значений, введенных в базу данных вручную, я уверен, что некоторые опечатки произошли и создали выбросы, например, измерение, которое должно читать 15.2, могло быть введено как 1.52 или 152 или 25.2. Я хотел бы идентифицировать эти выбросы, чтобы я мог их исправить, а не уничтожать, но существует слишком много видов, чтобы делать это в каждом конкретном случае. Как я могу автоматизировать и организовать результаты поиска выбросов для каждого подмножества измерений по каждому виду? Эта последняя часть имеет решающее значение, поскольку каждый вид может быть разного размера с радикально различными измерениями. Я пытаюсь максимально упростить процесс, поскольку это, скорее всего, будет происходить каждый раз, когда в базу данных добавляется новый пакет данных (или пока кто-то не найдет лицензию для создателя файла).

Я анализирую в R. Я думаю, что вложенный цикл for для всех значений, выходящих за 2 или 3 стандартных отклонения от среднего значения, сработает, и / или group_by с dplyr и функцией квантиля. Но я не смог понять, как запустить все столбцы одновременно, возвращая фактические значения выбросов. Есть целый ряд других вопросов, касающихся этих частей, но я не могу найти ни одного, который бы соединил все это.

Пример данных:

df = data.frame(
  species = c("a","b","a","b","a","b","a","b","a","b"),
  uniqueID = c("x01","x02","x03","x04","x05","x06","x07","x08","x09","x10"),
  metric1 = c(1,2,3,1,2,3,1,2,3,11),
  metric2 = c(4,5,6,4,5,6,55,4,5,6),
  metric3 = c(0.7,7,8,9,7,8,9,77,8,9)
)

Что касается ожидаемых результатов, я представляю данные типа data.frame или матрицы, уникальный_ID, измерение / столбец с выбросом и само значение выброса. Но то, как это отформатировано, менее важно, например.

outliers = data.frame(
  species = c("a","a","b","b"),
  uniqueID = c("x01","x07","x08","x10"),
  var = c("metric3","metric2","metric3","metric1"),
  value = c(0.7,55,77,11)
)

Заранее спасибо!

1 Ответ

0 голосов
/ 14 мая 2019

Для начала предоставим данные, которые вы предоставили ...

df = data.frame(
  species = c("a","b","a","b","a","b","a","b","a","b"),
  uniqueID = c("x01","x02","x03","x04","x05","x06","x07","x08","x09","x10"),
  metric1 = c(1,2,3,1,2,3,1,2,3,11),
  metric2 = c(4,5,6,4,5,6,55,4,5,6),
  metric3 = c(0.7,7,8,9,7,8,9,77,8,9)
)

Я собираюсь использовать здесь tidyverse свободно ...

library(tidyverse)

Затем, чтобы утроитьстрок, чтобы вычисление стандартного отклонения не отразилось на нас, и чтобы добавить еще одну выделенную строку ...

df2 <- df %>% 
  bind_rows(df) %>% 
  bind_rows(df) %>% 
  add_row(
    species = "a",
    uniqueID = "x01",
    metric1 = 1,
    metric2 = 4,
    metric3 = 1e12
  )

Что, если вы попробовали что-то подобное?

df2 %>% 
  gather(key = "metric", value = "value", -species, -uniqueID) %>% 
  group_by(species, uniqueID, metric) %>% 
  arrange(species, uniqueID, metric) %>% # just to make the results easy to scan
  mutate(
    mean_obs = mapply(function(x) mean(value[-x]), 1:n()),
    stdev    = mapply(function(x)   sd(value[-x]), 1:n()),
    minimum  = mean_obs - stdev * 2,
    maximum  = mean_obs + stdev * 2,
    outlier  = value < minimum | value > maximum
  ) %>% 
  filter(outlier) %>% 
  glimpse()

Это заимствуетиз этого ответа , чтобы найти среднее значение и стандартное отклонение , исключая текущую запись , а затем помечает строку как выброс, если строка превышает среднее значение на 2 SD.

Может быть странно, если вы исключите текущую запись, а запись будет не выбросом, и это заметно изменит среднее и стандартное отклонение.Но затем, если запись является выбросом, вы определенно захотите это сделать.:)

...