Quiero agregar una nueva columna al cuadro de datos a continuación que calcule la longitud máxima de período seco para cada mes. Así es como se ve mi marco de datos:

   day month year  rr spell spell1
     1     1 1981  0   dry      1
     2     1 1981  0   dry      1
     3     1 1981  0   dry      1
     4     1 1981  1.1 dry      0
     5     1 1981  0   dry      1
     6     1 1981  0   dry      1
     7     1 1981  0   dry      1
     8     1 1981  0   dry      1
     9     1 1981  2.7 dry      0
    10     1 1981  0   dry      1

Esta es la salida que necesito:

 month year  spell_length
     1 1981      3
     1 1981      4
     1 1981      1

Esto es lo que he hecho hasta ahora:

group_by(df, year, month, spell1) %>% 
    summarise(spell2 = sum(spell1, na.rm = TRUE))

Y este es el resultado:

  year month spell1 spell_length
  <int> <int>  <dbl>  <dbl>
1  1981     1      1     31
2  1981     2      0      0
3  1981     2      1     27
4  1981     3      0      0
5  1981     3      1     25
6  1981     4      0      0

datos

df <- read.table(h= T, text="day month year  rr spell spell1
1     1 1981  0   dry      1
2     1 1981  0   dry      1
3     1 1981  0   dry      1
4     1 1981  1.1 dry      0
5     1 1981  0   dry      1
6     1 1981  0   dry      1
7     1 1981  0   dry      1
8     1 1981  0   dry      1
9     1 1981  2.7 dry      0
10     1 1981  0   dry      1")
18
ahmad bello 10 may. 2019 a las 11:08

4 respuestas

La mejor respuesta

Una opción sería agrupar por 'run-length-id' de 'hechizo' (rleid desde data.table - crea una nueva identificación de agrupación cuando el valor cambia en esa columna), filter fuera de las filas que tienen 'hechizo1' es 0, obtenga el número de filas con n()

library(dplyr)
library(data.table)
df1 %>%
    group_by(year, month, grp = rleid(spell1)) %>%
    filter(spell1 ==1) %>%
    summarise(spell_length = n()) %>%
    ungroup %>%
    select(-grp)
# A tibble: 3 x 3
#   year month spell_length
#  <int> <int>        <int>
#1  1981     1            3
#2  1981     1            4
#3  1981     1            1

O use rle de base R

rl1 <- rle(df1$spell1)
rl1$lengths[rl1$values > 0]
#[1] 3 4 1

NOTA: Esta solución también funciona cuando los valores 'spell1' son diferentes

7
akrun 10 may. 2019 a las 08:18

Usando dplyr podemos crear grupos en cada aparición de 0 usando cumsum y sumar el número de spells en cada grupo.

library(dplyr)

df %>%
  group_by(month, year, group = cumsum(spell1 == 0)) %>%
  summarise(spell_length = sum(spell1)) %>%
  ungroup() %>%
  select(-group)

#    month  year spell_length
#   <int> <int>        <int>
#1     1  1981            3
#2     1  1981            4
#3     1  1981            1
7
Ronak Shah 10 may. 2019 a las 08:12

Usando la idea básica de @akrun pero sin data.table::rleid():

df %>%
 group_by(year, month, rleid = with(rle(spell1), rep(seq_along(lengths), lengths))) %>%
 filter(spell1 > 0) %>%
 ungroup() %>%
 count(month, year, rleid, name = "spell_length") %>%
 select(-rleid) 

  month  year spell_length
  <int> <int>        <int>
1     1  1981            3
2     1  1981            4
3     1  1981            1

O:

df %>%
 group_by(year, month, rleid = with(rle(spell1), rep(seq_along(lengths), lengths))) %>%
 filter(spell1 > 0) %>%
 summarise(spell_length = length(rleid)) %>%
 ungroup() %>%
 select(-rleid)
4
tmfmnk 10 may. 2019 a las 08:35

Aquí hay una opción usando dplyr::count:

library(dplyr)
count(df, month, year, grp = cumsum(spell1 == 0), zero = spell1==0) %>%
  filter(!zero) %>%
  select(-zero, - grp)

# # A tibble: 3 x 3
#   month  year     n
#   <int> <int> <int>
# 1     1  1981     3
# 2     1  1981     4
# 3     1  1981     1

O en la base R:

res <- aggregate(day ~  month + year + cumsum(spell1 == 0) + (spell1==0), df, length)
res[!res[[4]],-(3:4)]
#   month year day
# 1     1 1981   3
# 2     1 1981   4
# 3     1 1981   1
4
Moody_Mudskipper 10 may. 2019 a las 09:49