Очистка большого набора данных: как заполнить пропущенные данные на основе нескольких категорий и поиска по порядку строк - PullRequest
0 голосов
/ 12 сентября 2018

Это мой первый пост в StackOverflow, поэтому я надеюсь, что его не так сложно понять.

У меня большой набор данных (~ 14 000) строк наблюдений за птицами.Эти данные были собраны путем стояния в одном месте (точке) и подсчета птиц, которых вы видите в течение 3 минут.В пределах каждого подсчета точек новое наблюдение за птицами становится новой строкой, так что существует много повторяющихся дат, времени, мест и точек (определенное место внутри места).Опять же, каждое количество очков длится 3 минуты.Так что, если вы видите ye llow wa rbler (закодированный как YEWA) в течение минуты 1, то он будет связан с MINUTE = 1 для этого конкретного количества точек (дата, место, точка), и время). ID = данные наблюдателя и Number = количество обнаруженных птиц (здесь не обязательно это важно).

Однако, если NO BI RDS видны, то появляется "NOBI"входит в набор данных для этой конкретной минуты.Таким образом, если для всего трехминутного подсчета точек есть NOBI, их будет три строки с одинаковыми датой, местом, точкой и временем, а также «NOBI» в столбце «ПТИЦА» для каждой из трех строк.

Итак, у меня ДВА основные проблемы. first состоит в том, что некоторые наблюдатели вводили «NOBI» один раз за все три минуты, а не три раза (один раз в минуту).Везде, где «MINUTE» оставлено пустым (становится NA ) и «BIRD» = «NOBI», мне нужно добавить три строки данных, все с одинаковыми значениями для всех столбцов, кроме «MINUTE», что должно быть 1, 2 и 3 для соответствующих строк.

Если это выглядит так:

   ID     DATE SITE POINT TIME MINUTE BIRD NUMBER
1  BS 5/9/2018  CW2  U125 7:51     NA NOBI     NA
2  BS 5/9/2018  CW1  D250 8:12      1 YEWA     2
3  BS 5/9/2018  CW1  D250 8:12      2 NOBI     NA
4  BS 5/9/2018  CW1  D250 8:12      3 LABU     1

Это должно выглядеть следующим образом:

   ID     DATE SITE POINT TIME MINUTE BIRD NUMBER
1  BS 5/9/2018  CW2  U125 7:51      1 NOBI     NA
2  BS 5/9/2018  CW2  U125 7:51      2 NOBI     NA
3  BS 5/9/2018  CW2  U125 7:51      3 NOBI     NA
4  BS 5/9/2018  CW1  D250 8:12      1 YEWA     2
5  BS 5/9/2018  CW1  D250 8:12      2 NOBI     NA
6  BS 5/9/2018  CW1  D250 8:12      3 LABU     1

примечание: если вы хотите ввести некоторые из этих данных в консоль R, я включил некоторые в конец этого поста, используя dput, который должен быть проще для ввода, чем копирование и вставка вышеупомянутого

Я предпринял неудачные попытки воспроизведения операторов if с несколькими условиями (на основе: R нескольких условий в операторе if & Ifelse в R с несколькими категориальными условиями )Я попытался написать это разными способами, в том числе с помощью конвейера из dplyr, но ниже приведен пример кода, заметок и сообщений об ошибках.

>if(PC$BIRD == "NOBI" & PC$MINUTE==NA){PC$Fix<-TRUE}
 Error in if (PC$BIRD == "NOBI" & PC$MINUTE == NA) { : 
   missing value where TRUE/FALSE needed
 In addition: Warning message:
 In if (PC$BIRD == "NOBI" & PC$MINUTE == NA) { :
   the condition has length > 1 and only the first element will be used

## Then I need to do something like this:
>if(PC$Fix<-TRUE){duplicate(row where Fix==TRUE, times=2)} #I know this isn't 
    ### even close, but I want the row to be replicated two more times so 
    ### that there are 3 total rows witht he same values
    ### Fix indicates that a fix is needed in this example
# Then somehow I need to assign a 1 to PC$MINUTE for the first row (original row), 
# a 2 to the next row (with other values from other columns being the same), and a 3 
# to the last duplicated row (still other values from other columns being the same)

Проблема second , которая кажетсямне труднее искатьнабор данных по порядку или, возможно, по DATE, SITE, POINT и TIME в некотором роде.Минутные значения всегда должны быть от 1 ... до 2 ... до 3, а затем обратно до 1 для следующего набора даты, времени, места и точки.То есть каждый счетчик очков должен иметь все значения 1: 3.Однако один отсчет может иметь несколько визирований в MINUTE = 1, так что есть 5 или 6 (или 20) MINUTE = 1, прежде чем MINUTE = 2.НО, опять же, некоторые наблюдатели в этом наборе данных просто оставили строку, когда не было ПТИЦ (NOBI), вместо записи строки с BIRD = "NOBI" для каждой МИНУТЫ.То есть, если набор данных идет:

   ID     DATE SITE POINT TIME MINUTE BIRD NUMBER
...
4  BS 5/9/2018  CW2  U125 7:54      1 AMRO      1
5  BS 5/9/2018  CW2  U125 7:54      1 SPTO      1
6  BS 5/9/2018  CW2  U125 7:57      1 AMRO      1
7  BS 5/9/2018  CW2  U125 7:57      1 SPTO      1
8  BS 5/9/2018  CW2  U125 7:57      1 AMCR      3
9  BS 5/9/2018  CW2  U125 7:57      2 SPTO      1
10 BS 5/9/2018  CW2  U125 7:57      2 HOWR      1
11 BS 5/9/2018  CW2  U125 7:57      3 UNBI      1

Мы можем видеть, что время счета 7:57 завершено (есть значения МИНУТ 1: 3).Однако время счета 7:54 останавливается на МИНУТ = 1.Это означает, что мне нужно ввести еще две строки, которые имеют одинаковую информацию ДАТА, САЙТ, ТОЧКА, ВРЕМЯ, но с MINUTE = 2 и BIRD = "NOBI" для первой добавленной строки и MINUTE = 3 и BIRD = "NOBI"для второй добавленной строки.Таким образом, это должно выглядеть так:

   ID     DATE SITE POINT TIME MINUTE BIRD NUMBER
...
4  BS 5/9/2018  CW2  U125 7:54      1 AMRO      1
5  BS 5/9/2018  CW2  U125 7:54      1 SPTO      1
6  BS 5/9/2018  CW2  U125 7:54      2 NOBI      NA
7  BS 5/9/2018  CW2  U125 7:54      3 NOBI      NA
8  BS 5/9/2018  CW2  U125 7:57      1 AMRO      1
9  BS 5/9/2018  CW2  U125 7:57      1 SPTO      1
10 BS 5/9/2018  CW2  U125 7:57      1 AMCR      3
11 BS 5/9/2018  CW2  U125 7:57      2 SPTO      1
12 BS 5/9/2018  CW2  U125 7:57      2 HOWR      1
13 BS 5/9/2018  CW2  U125 7:57      3 UNBI      1

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


Все, что ниже этой строки, полезно только для вас, если вы хотите ввести образец моих данных в R


Чтобы ввести мои данные в консоль R, скопируйте и вставьте все, начиная от функции «структура» и заканчивая кодом, чтобы ввести его как консоль данных в консоли R с кодом: dataframe<-structure(list... См. Пример использования dput () для получения справки..

PC<-read.csv("PC.csv") ### ORIGINAL FILE
dput(PC)
structure(list(ID = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "BS", class = "factor"), 
DATE = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "5/9/2018", class = "factor"), 
SITE = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "CW2", class = "factor"), 
POINT = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("M", "U125"), class = "factor"), 
TIME = structure(c(8L, 8L, 8L, 9L, 9L, 10L, 10L, 10L, 10L, 
10L, 10L, 11L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 4L, 4L, 4L, 
4L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 7L), .Label = c("6:48", "6:51", 
"6:54", "6:57", "7:12", "7:15", "7:18", "7:51", "7:54", "7:57", 
"8:00"), class = "factor"), MINUTE = c(1L, 2L, 3L, 1L, 1L, 
1L, 1L, 1L, 2L, 2L, 3L, 1L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 1L, 
1L, 1L, 2L, 3L, 1L, 1L, 1L, 2L, 3L, 3L, NA, NA), BIRD = structure(c(6L, 
6L, 6L, 2L, 7L, 2L, 7L, 1L, 7L, 5L, 8L, 8L, 6L, 6L, 6L, 6L, 
6L, 6L, 7L, 7L, 7L, 7L, 6L, 8L, 3L, 7L, 9L, 5L, 4L, 2L, 6L, 
6L), .Label = c("AMCR", "AMRO", "BRSP", "DUFL", "HOWR", "NOBI", 
"SPTO", "UNBI", "VESP"), class = "factor"), NUMBER = c(NA, 
NA, NA, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, NA, NA, NA, NA, 
NA, NA, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, NA, 
NA)), class = "data.frame", row.names = c(NA, -32L))


PCc<-read.csv("PC_Corrected.csv")  #### WHAT I NEED MY DATABASE TO LOOK LIKE
dput(PCc)
structure(list(ID = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L), .Label = "BS", class = "factor"), DATE = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "5/9/2018", class = "factor"), 
SITE = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L), .Label = "CW2", class = "factor"), POINT = structure(c(2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("M", 
"U125"), class = "factor"), TIME = structure(c(8L, 8L, 8L, 
9L, 9L, 9L, 9L, 10L, 10L, 10L, 10L, 10L, 10L, 11L, 11L, 11L, 
1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 5L, 
5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 7L, 7L, 7L), .Label = c("6:48", 
"6:51", "6:54", "6:57", "7:12", "7:15", "7:18", "7:51", "7:54", 
"7:57", "8:00"), class = "factor"), MINUTE = c(1L, 2L, 3L, 
1L, 1L, 2L, 3L, 1L, 1L, 1L, 2L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 
3L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 1L, 1L, 2L, 3L, 1L, 1L, 1L, 
2L, 3L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), BIRD = structure(c(6L, 
6L, 6L, 2L, 7L, 6L, 6L, 2L, 7L, 1L, 7L, 5L, 8L, 8L, 6L, 6L, 
6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 6L, 6L, 7L, 7L, 6L, 8L, 3L, 
7L, 9L, 5L, 4L, 2L, 6L, 6L, 6L, 6L, 6L, 6L), .Label = c("AMCR", 
"AMRO", "BRSP", "DUFL", "HOWR", "NOBI", "SPTO", "UNBI", "VESP"
), class = "factor"), NUMBER = c(NA, NA, NA, 1L, 1L, NA, 
NA, 1L, 1L, 1L, 1L, 1L, 1L, 1L, NA, NA, NA, NA, NA, NA, NA, 
NA, 1L, 1L, NA, NA, 1L, 1L, NA, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
NA, NA, NA, NA, NA, NA)), class = "data.frame", row.names = c(NA, 
-42L))

1 Ответ

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

Вот способ сделать это, используя dplyr и tidyr из метапакета tidyverse.

# Step one - identify missing rows.
#    For each DATE, SITE, POINT, TIME, count how many of each minute 
library(tidyverse)

# Convert factors to character to make later joining simpler, 
#   and fix missing ID's by assuming prior line should be used,
#   and make NOBI rows have a count of NA
PC_2_clean <- PC %>%
  mutate_if(is.factor, as.character) %>%
  fill(ID, .direction = "up") %>%
  mutate(NUMBER = if_else(BIRD == "NOBI", NA_integer_, NUMBER))


# Create a wide table with spots for each minute. Missing will
#   show up as NA's
# All the NA's here in the 1, 2, and 3 columns represent 
#   missing minutes that we should add.
PC_3_NA_find <- PC_2_clean %>%
  count(ID, DATE, SITE, POINT, TIME, MINUTE) %>%
  spread(MINUTE, n)

PC_3_NA_find
# A tibble: 11 x 9
# ID    DATE     SITE  POINT TIME    `1`   `2`   `3` `<NA>`
# <chr> <chr>    <chr> <chr> <chr> <int> <int> <int>  <int>
#   1 BS    5/9/2018 CW2   M     7:12      3     1     2     NA
# 2 BS    5/9/2018 CW2   M     7:15     NA    NA    NA      1
# 3 BS    5/9/2018 CW2   M     7:18     NA    NA    NA      1
# 4 BS    5/9/2018 CW2   U125  6:48      1     1     1     NA
# 5 BS    5/9/2018 CW2   U125  6:51      1     1     1     NA
# 6 BS    5/9/2018 CW2   U125  6:54      2    NA    NA     NA
# 7 BS    5/9/2018 CW2   U125  6:57      2     1     1     NA
# 8 BS    5/9/2018 CW2   U125  7:51      1     1     1     NA
# 9 BS    5/9/2018 CW2   U125  7:54      2    NA    NA     NA
# 10 BS    5/9/2018 CW2   U125  7:57      3     2     1     NA
# 11 BS    5/9/2018 CW2   U125  8:00      1    NA    NA     NA


# Take the NA minute entries and make the desired line for each
PC_4_rows_to_add <- PC_3_NA_find %>%
  gather(MINUTE, count, `1`:`3`) %>%
  filter(is.na(count)) %>%
  select(-count, -`<NA>`) %>%

  mutate(MINUTE = as.integer(MINUTE),
         BIRD = "NOBI",
         NUMBER = NA_integer_)


# Add these lines to the original,  remove the NA minute rows 
#   (these have been replaced with minute rows), and sort
PC_5_with_NOBIs <- PC_2_clean %>%
  bind_rows(PC_4_rows_to_add) %>%
  filter(MINUTE != "NA") %>%
  arrange(ID, DATE, SITE, POINT, TIME, MINUTE, BIRD)


# Check result
PC_5_with_NOBIs  %>%
  count(ID, DATE, SITE, POINT, TIME, MINUTE) %>%
  spread(MINUTE, n)

PC_5_with_NOBIs



# Now to confirm it matches your desired output.
#   Note, I convert to character to avoid mismatches between factors
PCc_char <- PCc %>%
  mutate_if(is.factor, as.character) %>%
  arrange(ID, DATE, SITE, POINT, TIME, MINUTE, BIRD)

identical(PC_5_with_NOBIs, PCc_char)
# [1] TRUE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...