2 votes

Agrégation de la date et de l'heure pour résumer le temps passé dans certaines conditions "répétitives".

Bonne journée,

Il s'agit d'une question complémentaire à ce poste

Voici quelques données fictives :

Date <- as.POSIXct(c('2018-03-20 11:52:25', '2018-03-22 12:01:44', '2018-03-20 12:05:25', '2018-03-20 12:10:40', '2018-03-20 12:12:51 ', '2018-03-21 2:01:23', '2018-03-21 2:45:01', '2018-03-21 3:30:00', '2018-03-21 3:45:00', '2018-03-21 5:00:00', '2018-03-21 5:45:00')) 
Sites<-c(4, 4, 4, 6, 6, 7, 7, 4, 4, 6, 6)
Individual<-c("A", "A", "A", "A", "A", "A", "A", "A", "A", "A","A")

data<-data.frame(Individual, Date, Sites)

   Individual                Date Sites
           A 2018-03-20 11:52:25     4
           A 2018-03-22 12:01:44     4
           A 2018-03-20 12:05:25     4
           A 2018-03-20 12:10:40     6
           A 2018-03-20 12:12:51     6
           A 2018-03-21 02:01:23     7
           A 2018-03-21 02:45:01     7
           A 2018-03-21 03:30:00     4
           A 2018-03-21 03:45:00     4
           A 2018-03-21 05:00:00     6
           A 2018-03-21 05:45:00     6

En gros, je voudrais que R me dise combien de temps est passé sur chaque site. Les données ci-dessus ont des instances répétées sur les sites et j'aimerais que R fasse ressortir les répétitions et ajoute les différences de temps pour chacune.

J'ai essayé le code suivant :

data.summary<-data %>%
  group_by(Individual, Sites) %>%
  summarise(time_spent = max(Date)-min(Date))

Mais cela prendra une différence de temps entre la date minimale sur ce site et la date maximale sur le site, sans tenir compte des cas de répétition, ou des moments où l'individu est sur d'autres sites.

En creusant davantage dans les données fictives, le code de compression indique que l'individu A a passé 2 jours sur le site 4. Cependant, cet individu a quitté le site 4 et y est retourné à une date ultérieure. Le temps total passé sur le site 4 devrait être de 28 minutes. Comment puis-je faire en sorte que R reflète les entrées répétitives pour ce site ?

Date1<-as.POSIXct("2018-03-20 11:52:25") # First instance at site 4
Date2<-as.POSIXct("2018-03-20 12:05:25") # Last time A spent at site 4 before leaving
difftime(Date2, Date1, units="mins")
# time diff = 13 minutes

# Second instance at site 4
Date3<-as.POSIXct("2018-03-21 03:30:00") # Second instance at site 4
Date4<-as.POSIXct("2018-03-21 03:45:00") # Last time A spent at site 4
difftime(Date4, Date3, units="mins")
# time diff= 15 mins

Merci !

EDIT : Je trouve un problème avec dplyr summarise, où le temps supplémentaire est ajouté. Voici des données fictives :

Dates<-as.POSIXct(c("2018-04-09 16:59:03",
"2018-04-09 18:27:23",
"2018-04-09 17:01:20",
"2018-04-09 17:41:17"))
Individual<-c("A","A","A","A")
Site<-c("40","40","40", "40")

data<-data.frame(Dates, Individual, Site)

Je veux résumer le temps passé sur le site 40, avec l'horodatage minimum sur ce site soustrait de l'horodatage maximum sur le site.

data %>%
  group_by(Individual) %>%
  arrange(Dates) %>%
  group_by(Individual, Site) %>%   
  summarise(time_spent = max(Dates) - min(Dates))

   # A tibble: 1 x 3
# Groups:   Individual [?]
  Individual Site  time_spent    
  <fct>      <fct> <time>        
1 A          40    1.472222 hours 

Cela indique que le temps total passé sur ce site est de 1,47 heures. Cependant, lorsque j'obtiens manuellement un décalage horaire, j'obtiens une valeur totalement différente.

maxtime<-("2018-04-09 17:41:17")
mintime<-("2018-04-09 16:59:03")

difftime(maxtime, mintime, units="hours")
# Time difference of 0.7038889 hours 

Le temps réel sur le site 40 est de 0,70 heures. Je ne suis pas sûr de ce à quoi summarise fait référence, ou pourquoi le temps supplémentaire est ajouté.

EDIT 2 : Ok, cela ressemble à un problème d'unités ! Voici d'autres données reproductibles :

Dates<-as.POSIXct(c("2018-04-09 16:43:44","2018-03-20 11:52:25", "2018-04-09 16:59:03",
                    "2018-04-09 18:27:23",
                    "2018-04-09 17:01:20",
                    "2018-04-09 17:41:17"))
Individual<-c("A","A","A","A", "A","A")
Site<-c("38","38", "40","40","40", "40")

data<-data.frame(Dates, Individual, Site)
                Dates Individual Site
1 2018-04-09 16:43:44          A   38
2 2018-03-20 11:52:25          A   38
3 2018-04-09 16:59:03          A   40
4 2018-04-09 18:27:23          A   40
5 2018-04-09 17:01:20          A   40
6 2018-04-09 17:41:17          A   40

data %>%
  group_by(Individual) %>%
  arrange(Dates) %>%
  group_by(Individual, Site) %>%   
  summarise(time_spent = max(Dates) - min(Dates))
# A tibble: 2 x 3
# Groups:   Individual [?]
  Individual Site  time_spent    
  <fct>      <fct> <time>        
1 A          38    20.202303 days
2 A          40     1.472222 days

Ici, il est dit que le temps passé sur le site 40 est de 1,47 jours, mais cela devrait être des heures ! Selon la recherche manuelle des différences de temps ci-dessous :

maxtime<-("2018-04-09 18:27:23")
mintime<-("2018-04-09 16:59:03")

difftime(maxtime, mintime, units="hours")
# Time difference of 1.472222 hours  

Comment puis-je corriger ce problème d'unités ? Au lieu d'afficher les heures mélangées aux jours, je voudrais que R calcule le temps de tous les sites en jours.

1voto

Andrew Points 3280

SOLUTION MODIFIÉE : après quelques essais et erreurs, voici ce qui a fini par fonctionner. Ceci utilise une fonction de data.table Vous devez donc l'installer.

Étape 1 : créer un identifiant unique pour toutes les observations du site (par site), classées par Date

    data %>%
      arrange(Individuals, Dates) %>%
      mutate(rle_id = data.table::rleid(Sites))

                 Dates Individuals Sites rle_id
1  2018-03-20 11:52:25           A    38      1
2  2018-04-09 16:43:44           A    38      1
3  2018-04-09 16:59:03           A    40      2
4  2018-04-09 17:01:20           A    40      2
5  2018-04-09 17:41:17           A    40      2
6  2018-04-09 18:27:23           A    40      2
7  2018-03-20 11:52:25           B     4      3
8  2018-03-20 12:05:25           B     4      3
9  2018-03-20 12:10:40           B     6      4
10 2018-03-20 12:12:51           B     6      4
11 2018-03-21 02:01:23           B     7      5
12 2018-03-21 02:45:01           B     7      5
13 2018-03-21 03:30:00           B     4      6
14 2018-03-21 03:45:00           B     4      6
15 2018-03-21 05:00:00           B     6      7
16 2018-03-21 05:45:00           B     6      7
17 2018-03-22 12:01:44           B     4      8

Vous pourriez obtenir le relid en utilisant quelque chose en base comme ce que j'ai collé ci-dessous, mais c'est probablement beaucoup plus lent (et plus difficile à comprendre).

data <- data[order(data$Dates),]
rle_lengths <- rle(data$Sites)$lengths
unlist(Map(rep, 1:length(rle_lengths), rle_lengths))
[1] 1 2 2 3 3 4 4 5 5 6 6 7 8 9 9 9 9

vs.

data.table::rleid(data$Sites)
[1] 1 2 2 3 3 4 4 5 5 6 6 7 8 9 9 9 9

Étape 2 : obtenir le temps des individus A et B sur chaque site. Si nous n'avons pas spécifié les unités dans difftime, il fera le calcul sur les unités individuelles et affichera une unité commune. Par exemple, 1,5 heures devient 1,5 jours si une personne est présente pendant plusieurs jours.

data %>%
  arrange(Individuals, Dates) %>%
  mutate(rle_id = data.table::rleid(Sites)) %>%
  group_by(Individuals, rle_id, Sites) %>%
  summarise(time_spent = difftime(max(Dates), min(Dates), units = "days"))

# A tibble: 8 x 4
# Groups:   Individuals, rle_id [8]
  Individuals rle_id Sites time_spent       
  <fct>        <int> <dbl> <time>           
1 A                1    38 20.202303241 days
2 A                2    40  0.061342593 days
3 B                3     4  0.009027778 days
4 B                4     6  0.001516204 days
5 B                5     7  0.030300926 days
6 B                6     4  0.010416667 days
7 B                7     6  0.031250000 days
8 B                8     4  0.000000000 days

Étape 3 (solution complète) : effondrement à travers les sites

data %>%
  arrange(Individuals, Dates) %>%
  mutate(rle_id = data.table::rleid(Sites)) %>%
  group_by(Individuals, rle_id, Sites) %>%
  summarise(time_spent = difftime(max(Dates), min(Dates), units = "days")) %>%
  group_by(Individuals, Sites) %>%
  summarise(time_spent_new = sum(time_spent))

# A tibble: 5 x 3
# Groups:   Individuals [2]
  Individuals Sites time_spent_new  
  <fct>       <dbl> <time>          
1 A              38 20.20230324 days
2 A              40  0.06134259 days
3 B               4  0.01944444 days
4 B               6  0.03276620 days
5 B               7  0.03030093 days

Données

Date <-as.POSIXct(c("2018-04-09 16:43:44","2018-03-20 11:52:25", "2018-04-09 16:59:03",
                    "2018-04-09 18:27:23","2018-04-09 17:01:20", "2018-04-09 17:41:17",
                    '2018-03-20 11:52:25', '2018-03-22 12:01:44', '2018-03-20 12:05:25', 
                    '2018-03-20 12:10:40', '2018-03-20 12:12:51 ', '2018-03-21 2:01:23', 
                    '2018-03-21 2:45:01', '2018-03-21 3:30:00', '2018-03-21 3:45:00', 
                    '2018-03-21 5:00:00', '2018-03-21 5:45:00'))
Individual<-c(rep("A", 6), rep("B", 11))
Site<-c(38, 38, 40, 40, 40, 40, 4, 4, 4, 6, 6, 7, 7, 4, 4, 6, 6)

data<-data.frame(Dates = Date, Individuals = Individual, Sites = Site)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X