обобщение данных о температуре на основе вектора температурных порогов

У меня есть фрейм данных со среднесуточной температурой в нем, структурированный так:

 'data.frame':  4666 obs. of  6 variables:
 $ Site : chr  "EB" "FFCE" "IB" "FFCE" ...
 $ Date : Date, format: "2013-01-01" "2013-01-01" "2013-01-01" "2014-01-01" ... 
 $ Day  : int  1 1 1 1 1 1 1 1 1 1 ...
 $ Year : int  2013 2013 2013 2014 2014 2014 2014 2015 2015 2015 ...
 $ Month: int  1 1 1 1 1 1 1 1 1 1 ...
 $ Temp : num  28.5 28.3 28.3 27 27.8 ...

Я пытаюсь создать сводную таблицу, которая просто суммирует количество дней в году на сайте выше определенных пороговых значений температуры, например 25c, 26c. Я могу добиться этого вручную, используя dplyr, например:

Days_above = Site_Daily_average %>% 
  group_by(Year, Site) %>% 
  summarise("23" = sum(Temp > 23), "24" = sum(Temp > 24),"25"= sum(Temp > 
25), "26"= sum(Temp > 26),  "27"= sum(Temp > 27), "28"= sum(Temp > 28), "29" 
= sum(Temp > 29),"30"= sum(Temp > 30), "31" = sum(Temp > 31), "ABOVE 
THRESHOLD" = sum(Temp > maxthreshold))%>% as.data.frame()  

В результате получается такая таблица:

   Year Site  23  24  25  26  27  28  29 30 31 ABOVE THRESHOLD
1  2012   EB 142 142 142  91  64  22   0  0  0               0
2  2012 FFCE 238 238 238 210 119  64   0  0  0               0
3  2012   IB 238 238 238 218 138  87   1  0  0               0
4  2013   EB 115 115 115 115 115 109  44  0  0               0
5  2013 FFCE 223 223 216 197 148 114  94  0  0               0
6  2013   IB 365 365 365 348 299 194 135  3  0               0

...

однако, как видите, код довольно подробный. Проблема, с которой я столкнулся, создает тот же результат для последовательности пороговых значений температуры, то есть Tempclasses = Seq (16,32,0,25).

Как видите, на ввод вручную потребуется много времени. Мне кажется, что это очень простое вычисление, и должен быть способ использовать dplyr для распознавания каждой переменной в векторе последовательности, выполнения этой функции и создания вывода в формате полной таблицы. извините, если это было неясно, так как я относительно новичок в R, любые предложения будут приветствоваться, спасибо.


person K.west    schedule 22.05.2018    source источник


Ответы (2)


Вот подход tidyverse, также использующий mtcars для иллюстрации:

library(tidyverse)

mtcars %>% 
  mutate(threshold = cut(mpg, 
                         breaks=seq(10, max(mtcars$mpg)+10, 5), 
                         labels=seq(10, max(mtcars$mpg)+5, 5))) %>% 
  group_by(cyl, threshold) %>% 
  tally %>% 
  ungroup %>% 
  complete(threshold, nesting(cyl), fill=list(n=0)) %>% 
  arrange(desc(threshold)) %>% 
  group_by(cyl) %>% 
  mutate(N_above = cumsum(n)) %>% 
  select(-n) %>% 
  arrange(cyl, threshold)
   threshold cyl N_above
1         10   4      11
2         15   4      11
3         20   4      11
4         25   4       6
5         30   4       4
6         35   4       0
7         10   6       7
8         15   6       7
9         20   6       3
10        25   6       0
11        30   6       0
12        35   6       0
13        10   8      14
14        15   8       8
15        20   8       0
16        25   8       0
17        30   8       0
18        35   8       0

Если вы хотите, чтобы окончательные данные были в широком формате, добавьте spread в конце и удалите arrange:

... %>%
select(-n) %>% 
spread(threshold, N_above)
  cyl 10 15 20 25 30 35
1   4 11 11 11  6  4  0
2   6  7  7  3  0  0  0
3   8 14  8  0  0  0  0
person eipi10    schedule 22.05.2018
comment
о, я пробовал использовать спред раньше, но, видимо, не организовал его должным образом, большое спасибо, это круто - person K.west; 22.05.2018
comment
Я только что понял, что у меня перевернутая кончина по сравнению с вашим примером. Вы хотите, чтобы количество дней было выше, а не ниже порогового значения? При желании я могу обновить свой ответ. - person eipi10; 22.05.2018
comment
желательно выше, если все в порядке - person K.west; 22.05.2018

Как прокомментировал @dww, мы можем использовать cut для получения требуемого формата. Я пробовал это в наборе данных mtcars, где мы создаем диапазон от 10 до 35 с шагом 5 для столбца mpg.

df <- mtcars
df$group <- cut(df$mpg, seq(10, 35, 5))

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

table(df$cyl, df$group)

#  (10,15] (15,20] (20,25] (25,30] (30,35]
#4       0       0       5       2       4
#6       0       4       3       0       0
#8       6       8       0       0       0

Теперь, если определенное значение больше 10, оно также больше 15, следовательно, число в ведре (15, 20) должно также включать номер из ведра (10,15), а число в ведре (20, 15) должно включать оба предыдущий номер. Следовательно, для этой таблицы нам понадобится построчное cumsum

t(apply(table(df$cyl, df$group), 1, cumsum))

#   (10,15] (15,20] (20,25] (25,30] (30,35]
# 4       0       0       5       7      11
# 6       0       4       7       7       7
# 8       6      14      14      14      14

В вашем случае код будет идти

Site_Daily_average$group <- cut(Site_Daily_average$Temp, seq(16,32,0.25))

#and then do table to get required answer.
t(apply(table(Site_Daily_average$Year,Site_Daily_average$Site, 
              Site_Daily_average$group), 1, cumsum)
person Ronak Shah    schedule 22.05.2018
comment
о, хорошо, так это обеспечивает подсчет температуры в температурных классах, определенных последовательностью? то, что я пытался достичь, - это подсчитать общее количество наблюдений над каждым отдельным значением в этой последовательности, а не подсчет для каждого температурного класса, имеет ли это смысл? Я не уверен, что объясняю это четко - person K.west; 22.05.2018
comment
ох ... подождите, чтобы sum(Temp > 24) также имел значения из sum(Temp > 23) и так далее. Число будет увеличиваться постепенно в каждой строке? - person Ronak Shah; 22.05.2018
comment
не совсем, я думаю, что сбивает с толку то, что сумма (Temp ›24) - это слегка обманчивая формула, потому что (насколько я понимаю) это логический тест, который предоставляет Сумму количества точек данных, которые являются ИСТИННЫМИ для этого выражения (т.е. более 24 с), вместо того, чтобы фактически давать вам сумму, поэтому он фактически дает вам количество логических истинных точек данных? Имеет ли это смысл? По какой-то причине у меня возникли проблемы с использованием «счетчика» и «длины». это имеет больше смысла, мне, по сути, нужен `` Подсчет '' всех температур выше значений в последовательности / - person K.west; 22.05.2018
comment
Да, именно так. Таким образом, любое число, которое больше 24, также больше, чем 23. Таким образом, sum(Temp > 24) всегда будет больше или равно sum(Temp > 23). Я отредактировал ответ, посмотрим, есть ли в нем смысл. - person Ronak Shah; 22.05.2018