Перестройка значений в неравных сегментах путем агрегирования по столбцу в R - PullRequest
1 голос
/ 06 февраля 2020

У меня есть набор данных, который выглядит так, как показано ниже:

| Id |  Name | Date_diff |
|----|:-----:|----------:|
| 50 | David |  0        |
| 50 | David | -16       |
| 50 | David | -4        |
| 50 | David | -1        |
| 50 | David |  0        |
| 50 | David | -2        |
| 84 | Ron   | -11       |
| 84 | Ron   | -12       |
| 84 | Ron   | -168      |
| 84 | Ron   | -8        |
| 84 | Ron   | 16        |
| 84 | Ron   | NA        |

Воспроизводимый код:

df= data.frame(Id= c('50','84'), Name= c('David','Ron'))
df=df[rep(seq_len(nrow(df)),each=6),]
Date_diff= c(0,-16,-4,-1,0,-2,-11,-12,-168,-8,16,'NA')
df=data.frame(df,Date_diff)

Теперь для каждого идентификатора мне нужно создать разные столбцы неравных сегменты, в которых будет указано количество значений в столбце «Date-diff». Диапазоны интервалов должны быть «NA», «> 0», «0», «- 1», «от 2 до -3», «от 4 до 6», «от 7 до 12» и «> -12' . Также будет дополнительный столбец «итого», в котором будут храниться суммированные значения, присутствующие в сегментах.

Например, когда мы рассматриваем Id = 50, мы видим, что есть 2 счетчика для значения «0», которые попадают в сегмент «0», 1 счетчик для значения «-16», которое будет попадать в область «> 0», 1 считать значение -4, которое попадет в диапазон от -4 до -6, и так далее. Окончательная таблица должна быть такой, как показано ниже:

| Id |  Name | NA | >0 | 0 | -1 | -2 to -3 | -4 to -6 | -7 to -12 | >-12 | Total |
|----|:-----:|---:|----|---|----|----------|----------|-----------|------|-------|
| 50 | David |  0 | 0  | 2 | 1  | 1        | 1        | 0         | 1    | 6     |
| 84 |  Ron  |  1 | 1  | 0 | 0  | 0        | 0        | 3         | 1    | 6     |

Сначала я попытался создать новый столбец, чтобы классифицировать в нем значения в Date_diff, но значения, представленные в перерывах, вероятно, неверны. Вот что я попробовал:

df <- transform(df, group=cut(Date_diff,  breaks=c(-Inf,-13,-7,-4,-2,-1,Inf),
                               labels=c('<-12', '-7 to -12','-4 to -6','-2 to -3', '-1','>0')))

Может кто-нибудь, пожалуйста, дайте мне знать, как добиться желаемого результата?

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Одной из проблем было использование 'NA' в виде строки символов вместо NA. Вот решение с:

df <- data.frame(
  id = c('50', '84'),  
  name = c('david', 'ron'),
  date_diff = c(0, -16, -4, -1, 0, -2, -11, -12, -168, -8, 16,  na)
)

library(dplyr)
library(tidyr)

df %>%
  mutate(
    group = cut(
      Date_diff,
      breaks = c(-Inf,-13,-7,-4,-2,-1,Inf),
      labels = c('<-12', '-7 to -12','-4 to -6','-2 to -3', '-1','>0')
    ),
    group = if_else(is.na(group), "NA", as.character(group))
  ) %>%
  group_by(Id, Name, group) %>%
  summarise(n = n()) %>%
  mutate(Total = sum(n, na.rm = T)) %>%
  pivot_wider(names_from = group, values_from = n)
0 голосов
/ 07 февраля 2020

Исходное cut назначение может работать с помощью within для переназначения специальных групп, table для подсчета значений по группам вырезов и reshape для преобразования длинного в широкоформатный формат

cut + within

# CREATE CUT COLUMN
df <- within(df, {
         Group <- as.character(cut(Date_diff,  
                                   breaks=c(-Inf,-13,-7,-4,-2,-1,Inf),
                                   labels=c('<-12','-7 to -12','-4 to -6',
                                            '-2 to -3','-1','>0')))

         # ADJUST FOR ZERO AND ONE GROUPING
         Group <- ifelse(Date_diff == 0, "0", ifelse(Date_diff == 1, "1", Group))
     })

# TABULATE COUNTS 
tbl_df <- transform(data.frame(table(Name=df$Name, Group = df$Group, useNA = "ifany"), 
                               stringsAsFactors = FALSE),
                    Group = ifelse(is.na(Group), "NA", as.character(Group)))

# RESHAPE
final_df <- reshape(tbl_df, v.names = "Freq", timevar = "Group", idvar = "Name",
                    direction = "wide", sep = "_")

# REORDER AND RENAME COLUMNS
cols <- c("NA", ">0", "0", "-1", "-2 to -3", "-4 to -6", "-7 to -12", "<-12")
final_df <- setNames(final_df[c("Name", paste0("Freq_", cols))],
                     c("Name", gsub("Freq_", "", cols)))

# ADD TOTAL AND ID COLUMNS
final_df$Total <- rowSums(final_df[-1])
final_df <- merge(unique(df[c("Id", "Name")]), final_df, by="Name")[c("Id", "Name", cols)]

Выход

final_df
#    Name Id NA >0 0 -1 -2 to -3 -4 to -6 -7 to -12 <-12 Total
# 1 David 50  0  0 2  1        1        1         0    1     6
# 2   Ron 84  1  1 0  0        0        0         3    1     6

Онлайн-демонстрация

...