Подсчет значений за год и на основе других столбцов - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть такие данные

  Chemical  date      concentration  limit
   A     01-01-2016     0.2         0.01
   A     01-02-2016     0.2         0.01
   A     01-01-2017     0.005       0.01
   A     01-02-2017     0.2         0.01
   B     01-01-2016     0.3         0.1
   B     01-02-2016     0.05        0.1
   B     01-01-2017     0.2         0.1
   B     01-02-2017     0.2         0.1
   C     01-01-2016     1.2         1
   C     01-02-2016     0.8         1
   C     01-01-2017     0.9         1
   C     01-02-2017     0.9         1

Я хочу посчитать, сколько раз каждое химическое вещество превышает лимит в год (обратите внимание, что каждый лимит отличается).Поэтому я хотел бы получить что-то вроде этого

  Year   A     B    C
  2016   2     1    1
  2017   1     2    0

и, наконец, все превышения в год, поэтому

 Year exceedances
 2016   4
 2017   3

Я не уверен, как это сделать в R. Надеюсь, вы можетеПомогите.

Ответы [ 6 ]

0 голосов
/ 14 декабря 2018

Использование tidyverse с данными @ akrun:

library(tidyverse)
df1 %>% 
  filter(concentration > limit) %>%
  count(Chemical, Year=substr(date,7,10)) %>%
  spread(Chemical,n,fill = 0)
# # A tibble: 2 x 4
#    Year     A     B     C
# * <chr> <dbl> <dbl> <dbl>
# 1  2016     2     1     1
# 2  2017     1     2     0

df1 %>% 
  filter(concentration > limit) %>%
  count(Year=substr(date,7,10))
# A tibble: 2 x 2
#    Year     n
#   <chr> <int>
# 1  2016     4
# 2  2017     3
0 голосов
/ 13 декабря 2018

Еще одна возможность:

library(dplyr)
library(tidyr)
#library(lubridate) # you can choose to import it or not


dat %>% 
  mutate(date = lubridate::dmy(format(date, format="%d-%m-%Y"))) %>% # correct date format
  mutate(year = lubridate::year(date)) %>%  # extract the year
  group_by(year, Chemical) %>% 
  mutate(exceed = concentration > limit) %>% # TRUE/FALSE
  summarise(tot_exceed = sum(exceed)) %>%  # count each T/F
  spread(Chemical, tot_exceed) # Spread the results by Chemical
# # A tibble: 2 x 4
# # Groups:   year [2]
# year     A     B     C
# <dbl> <int> <int> <int>
# 1  2016     2     1     1
# 2  2017     1     2     0

Данные:

tt <- "  Chemical  date      concentration  limit
   A     01-01-2016     0.2         0.01
A     01-02-2016     0.2         0.01
A     01-01-2017     0.005       0.01
A     01-02-2017     0.2         0.01
B     01-01-2016     0.3         0.1
B     01-02-2016     0.05        0.1
B     01-01-2017     0.2         0.1
B     01-02-2017     0.2         0.1
C     01-01-2016     1.2         1
C     01-02-2016     0.8         1
C     01-01-2017     0.9         1
C     01-02-2017     0.9         1"

dat <- read.table(text = tt, header = T)
0 голосов
/ 13 декабря 2018

Другой вариант tidyverse,

library(tidyverse)

df %>% 
 filter(concentration > limit) %>% 
 group_by(Chemical, grp = format(as.POSIXct(date, format = '%m-%d-%Y'), format = '%Y')) %>% 
 count() %>% 
 spread(Chemical, n, fill = 0)

, который дает,

# A tibble: 2 x 4
# Groups:   grp [2]
  grp       A     B     C
  <chr> <dbl> <dbl> <dbl>
1 2016      2     1     1
2 2017      1     2     0
0 голосов
/ 13 декабря 2018

С помощью data.table мы преобразуем «data.frame» в «data.table» (setDT(df1)), сгруппированные по классам year из Date, преобразованным «date» и «chemical», получимsum логического вектора и dcast его в «широкий» формат

library(data.table)
library(lubridate)
dcast(setDT(df1)[, sum(concentration > limit),
      .(date = year(dmy(date)), Chemical)], date ~ Chemical)
#   date A B C
#1: 2016 2 1 1
#2: 2017 1 2 0

или с использованием base R с xtabs

xtabs(cond ~ date + Chemical, transform(df1, date = substr(date, 7, 10), 
                 cond = concentration > limit))
#      Chemical
#date   A B C
#  2016 2 1 1
#  2017 1 2 0

data

df1 <- structure(list(Chemical = c("A", "A", "A", "A", "B", "B", "B", 
"B", "C", "C", "C", "C"), date = c("01-01-2016", "01-02-2016", 
"01-01-2017", "01-02-2017", "01-01-2016", "01-02-2016", "01-01-2017", 
"01-02-2017", "01-01-2016", "01-02-2016", "01-01-2017", "01-02-2017"
 ), concentration = c(0.2, 0.2, 0.005, 0.2, 0.3, 0.05, 0.2, 0.2, 
 1.2, 0.8, 0.9, 0.9), limit = c(0.01, 0.01, 0.01, 0.01, 0.1, 0.1, 
 0.1, 0.1, 1, 1, 1, 1)), class = "data.frame", row.names = c(NA, 
  -12L))
0 голосов
/ 13 декабря 2018

Вот решение с использованием пакета dplyr:

library(dplyr)
chemical <- c('A','A','A','A','B','B','B','B','C','C','C','C')
date <- c('01-01-2016', '01-02-2016', '01-01-2017', '01-02-2017', '01-01-2016', '01-02-2016', '01-01-2017', '01-02-2017', '01-01-2016', '01-02-2016', '01-01-2017', '01-02-2017')
year <- format(as.Date(df$date, format="%m-%d-%Y"),"%Y")
concentration <- c(0.2, 0.2, 0.005, 0.2, 0.3, 0.05, 0.2, 0.2, 1.2, 0.8, 0.9, 0.9)
limit <- c(0.01, 0.01, 0.01, 0.01, 0.1, 0.1, 0.1, 0.1, 1, 1, 1, 1)

df <- data.frame(chemical, date, year, concentration, limit)

df_1 <- df %>% mutate(exceed = concentration>limit) %>% filter(exceed==T)

df_2 <- df_1 %>% group_by(chemical, year) %>% count(exceed)

df_2:

  chemical year  exceed     n
  <fct>    <fct> <lgl>  <int>
1 A        2016  TRUE       2
2 A        2017  TRUE       1
3 B        2016  TRUE       1
4 B        2017  TRUE       2
5 C        2016  TRUE       1

df_3 <- df_2 %>% group_by(year) %>% count(exceed)

df_3:

  year  exceed    nn
  <fct> <lgl>  <int>
1 2016  TRUE       3
2 2017  TRUE       2
0 голосов
/ 13 декабря 2018

Используя tidyverse и reshape2 вы можете сделать:

df %>%
 mutate(date = substr(date, 7, 10)) %>%
 group_by(date, Chemical) %>%
 summarise(temp = sum(ifelse(concentration > limit, 1, 0))) %>%
 dcast(date~Chemical, value.var = "temp")

  date A B C
1 2016 2 1 1
2 2017 1 2 0
...