Создайте группы, разрывы и условия, используя операторы If Else в R или Python - PullRequest
0 голосов
/ 29 февраля 2020

У меня есть большой набор данных (2 миллиона записей), df, который я пытаюсь сгруппировать и создать разрывы в пределах времени. Я хотел бы определить группу и создать эти "разрывы", если применяются следующие условия: (Это большой набор данных, и я не знаю содержимого столбцов темы, получателей и длины)

 If the edit == "T"
 If the message is ""
 If the folder is "out" or "draft"

Я бы хотел сопоставить эти группы, если последние значения столбца длины соответствуют значениям следующих групп, первой строки столбца длины. Так, например, значение '80' связывает группы, а редактирование - это T, папка отсутствует или черновик, а сообщение пустое.

 subject    recipient                  length   folder    message  date                       edit
                                        80      out                1/2/2020 1:00:01 AM        T                                    
                                        80      out                1/2/2020 1:00:05 AM        T                   
hey        sarah@mail.com,g@mail.com    80      out                1/2/2020 1:00:10 AM        T
hey        sarah@mail.com,g@mail.com    80      out                1/2/2020 1:00:15 AM        T
hey        sarah@mail.com,g@mail.com    80      out                1/2/2020 1:00:30 AM        T
some       k                           900      in       jjjjj     1/2/2020 1:00:35 AM        F
some       k                           900      in       jjjjj     1/2/2020 1:00:36 AM        F 
some       k                           900      in       jjjjj     1/2/2020 1:00:37 AM        F
hey        sarah@mail.com,g@mail.com    80    draft                1/2/2020 1:02:00 AM        T
hey        sarah@mail.com,g@mail.com    80    draft                1/2/2020 1:02:05 AM        T    
no         a                          900       in        iii      1/2/2020 1:02:10 AM        F
no         a                          900       in        iii      1/2/2020 1:02:15 AM        F
no         a                          900       in        iii      1/2/2020 1:02:20 AM        F
no         a                          900       in        iii      1/2/2020 1:02:25 AM        F
hey        sarah@mail.com,g@mail.com   80    draft                 1/2/2020 1:03:00 AM        T
hey        sarah@mail.com,g@mail.com   80    draft                 1/2/2020 1:03:20 AM        T

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

Это желаемый вывод:

 Start                  End                        Duration          Group  Subject  Length
 1/2/2020 1:00:01 AM    1/2/2020 1:00:30 AM        29                A      hey       80
 1/2/2020 1:02:00 AM    1/2/2020 1:02:05 AM        5                 A      hey       80
 1/2/2020 1:03:00 AM    1/2/2020 1:03:20 AM        20                A      hey       80

Все они находятся в одной группе A потому что последняя строка столбца длины соответствует первой строке столбца длины следующей группы.

library(tidyverse)
library(lubridate)





df$Date <- lubridate::dmy_hms(df$Date)

df <- mutate_if(df, is.factor, as.character)


df$GROUP <- "Edit == "T", Folder == "out"|"draft", Message == """
df$BREAK_DETECTOR <- ""
group_count <- 0
break_count <- 0
for (i in 1:nrow(df)) {



if (i == 1) {
group_count <- group_count + 1
df$GROUP[[i]] <- letters[[group_count]]
}
if (i > 1) {
if (df$GROUP[[i - 1]] != "") {
  df$GROUP[[i]] <- df$GROUP[[i - 1]]
} else {
  group_count <- group_count + 1
  df$GROUP[[i]] <- letters[[group_count]]
 }
 }
   if (i == 1) {
   break_count <- break_count + 1
df$BREAK_DETECTOR[[i]] <- break_count
 } else { #rules for detecting breaks - I chose to make it depend on NA values in the Length field
if (is.na(df$Length[[i]])) {
  if (!is.na(df$Length[[i - 1]])) { # and only if the previous line isnt also NA for Length
    break_count <- break_count + 1
  }
}
df$BREAK_DETECTOR[[i]] <- break_count
   }
 }


  df2 <- df %>%
  filter(!is.na(Length)) %>%
  group_by(
 GROUP, BREAK_DETECTOR
) %>%
summarise(
start = min(Date),
end = max(Date),
duration = difftime(end, start, units = "secs"),
min_subject = min(Subject),
max_subject = max(Subject),
min_recipient = min(Recipient),
max_recipient = max(Recipient),
min_length = min(Length),
max_length = max(Length)
) %>%
  ungroup()

Вот результат для этого:

structure(list(Subject = structure(c(1L, 1L, 2L, 2L, 2L, 4L, 
4L, 4L, 2L, 2L, 3L, 3L, 3L, 3L, 2L, 2L, 1L, 1L), .Label = c("", 
"hey", "no", "some"), class = "factor"), Recipient = structure(c(1L, 
1L, 5L, 5L, 5L, 4L, 4L, 4L, 5L, 5L, 3L, 3L, 3L, 3L, 5L, 5L, 1L, 
2L), .Label = c("", " ", "a", "k", "sarah@mail.com,gee@mail.com"
), class = "factor"), Length = c(80L, 80L, 80L, 80L, 80L, 900L, 
900L, 900L, 80L, 80L, 900L, 900L, 900L, 900L, 80L, 80L, NA, NA
), Folder = structure(c(4L, 4L, 4L, 4L, 4L, 3L, 3L, 3L, 2L, 2L, 
3L, 3L, 3L, 3L, 2L, 2L, 1L, 1L), .Label = c("", "draft", "in", 
"out"), class = "factor"), Message = structure(c(1L, 1L, 1L, 
1L, 1L, 2L, 2L, 2L, 1L, 1L, 3L, 3L, 3L, 3L, 1L, 1L, 1L, 1L), .Label = c("", 
 "jjjjjjj", "llll"), class = "factor"), Date = structure(c(2L, 
3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 
17L, 1L, 1L), .Label = c("", "1/2/2020 1:00:01 AM", "1/2/2020 1:00:05 AM", 
"1/2/2020 1:00:10 AM", "1/2/2020 1:00:15 AM", "1/2/2020 1:00:30 AM", 
"1/2/2020 1:00:35 AM", "1/2/2020 1:00:36 AM", "1/2/2020 1:00:37 AM", 
 "1/2/2020 1:02:00 AM", "1/2/2020 1:02:05 AM", "1/2/2020 1:02:10 AM", 
"1/2/2020 1:02:15 AM", "1/2/2020 1:02:20 AM", "1/2/2020 1:02:25 AM", 
"1/2/2020 1:03:00 AM", "1/2/2020 1:03:20 AM"), class = "factor"), 
 Edit = c(TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, 
 TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, NA, NA
 )), class = "data.frame", row.names = c(NA, -18L))

1 Ответ

2 голосов
/ 29 февраля 2020

Использование dplyr:

library(dplyr)

df %>%
  #Add row number
  mutate(row = row_number(), 
  #Convert to Posixct
         Date = lubridate::mdy_hms(Date)) %>%
  #Keep only TRUE rows
  filter(Edit) %>%
  #Create groups
  group_by(gr = cumsum(c(TRUE, diff(row) > 1))) %>%
  #Get first, last and difference between the dates
  summarise(Start = first(Date), 
            End = last(Date), 
            Duration = difftime(End, Start, "secs"), 
            Group = "A", Subject = "hey", Length = 80) %>%
   select(-gr)

# A tibble: 3 x 6
#  Start               End                 Duration Group Subject Length
#  <dttm>              <dttm>              <drtn>   <chr> <chr>    <dbl>
#1 2020-01-02 01:00:01 2020-01-02 01:00:30 29 secs  A     hey         80
#2 2020-01-02 01:02:00 2020-01-02 01:02:05  5 secs  A     hey         80
#3 2020-01-02 01:03:00 2020-01-02 01:03:20 20 secs  A     hey         80
...