1
votes

Comment sélectionner parmi 4 colonnes deux consécutives avec la plage maximale et la diviser entre la plage maximale trouvée entre l'une des 4 colonnes

J'ai df1 qui résume différents datetimes au fil du temps et df2 qui résume différentes températures de l'eau à différentes profondeurs au fil du temps. Je souhaite ajouter une nouvelle colonne dans df1 appelée Prop_rangeT qui, pour une date / heure spécifique, est égale à la plage maximale entre DEUX COLONNES CONSÉCUTIVES divisée entre la plage maximale en considérant l'un des quatre colonnes dans df2 pour la même date / heure que df1 . Par exemple:

df1
             DateTime Prop_rangeT
1 2016-08-01 08:01:17   0.3636364 # For instance, this is 4/11
2 2016-08-01 09:17:14   0,3565217
3 2016-08-01 10:29:31   0,3773585
4 2016-08-01 11:35:02   0.4174757
5 2016-08-01 12:22:45   0.6018519
6 2016-08-01 13:19:27   0.5200000
7 2016-08-01 14:58:17   0.5918367 # For instance, this is 5.8/9.8
8 2016-08-01 15:30:10   0.5833333

Comment pourrais-je obtenir la colonne df1 $ Prop_rangeT avec le code le plus simple? À titre d'exemple de ce que j'aimerais obtenir:

df1<- data.frame(DateTime=c("2016-08-01 08:01:17","2016-08-01 09:17:14","2016-08-01 10:29:31","2016-08-01 11:35:02","2016-08-01 12:22:45","2016-08-01 13:19:27","2016-08-01 14:58:17","2016-08-01 15:30:10"))
df1$DateTime<- as.POSIXct(df1$DateTime, format = "%Y-%m-%d %H:%M:%S", tz= "UTC")
df2<- data.frame(DateTime=c("2016-08-01 08:00:00","2016-08-01 09:00:00","2016-08-01 10:00:00","2016-08-01 11:00:00","2016-08-01 12:00:00","2016-08-01 13:00:00","2016-08-01 14:00:00","2016-08-01 15:00:00"),T5=c(27.0,27.5,27.1,27.0,26.8,26.3,26.0,26.3),T15=c(23.0,23.4,23.1,22.7,22.5,21.5,22.0,22.3),T25=c(19.0,20.0,19.5,19.6,16.0,16.3,16.2,16.7),T35=c(16.0,16.0,16.5,16.7,16.3,16.7,16.9,16.7))
df2$DateTime<- as.POSIXct(df2$DateTime, format = "%Y-%m-%d %H:%M:%S", tz= "UTC")

df1
             DateTime
1 2016-08-01 08:01:17
2 2016-08-01 09:17:14
3 2016-08-01 10:29:31
4 2016-08-01 11:35:02
5 2016-08-01 12:22:45
6 2016-08-01 13:19:27
7 2016-08-01 14:58:17
8 2016-08-01 15:30:10

df2
             DateTime   T5  T15  T25  T35
1 2016-08-01 08:00:00 27.0 23.0 19.0 16.0 # Here max range is between T35 ans T5 (11) and the max range between two consecutive columns is either T15 and T5 or T25 and T15 (4).
2 2016-08-01 09:00:00 27.5 23.4 20.0 16.0
3 2016-08-01 10:00:00 27.1 23.1 19.5 16.5
4 2016-08-01 11:00:00 27.0 22.7 19.6 16.7
5 2016-08-01 12:00:00 26.8 22.5 16.0 16.3
6 2016-08-01 13:00:00 26.3 21.5 16.3 16.7
7 2016-08-01 14:00:00 26.0 22.0 16.2 16.9 # In this case, max range is between T25 and T5 (9.8), and the max range between two consecutive columns correspond to T25 and T15 (5.8).
8 2016-08-01 15:00:00 26.3 22.3 16.7 16.7

r

0 commentaires

4 Réponses :


1
votes

Je pense que cela fonctionne. Rien d'extraordinaire ici. J'ai écrit chaque différence, puis j'ai ajouté quelques calculs par ligne .

library(dplyr)
library(lubridate)

df1 %>% 
  mutate(FloorDate = floor_date(DateTime, unit = "hour")) %>% 
  left_join(df2, by = c("FloorDate" = "DateTime")) %>% 
  mutate(ConsDiff1 = abs(T5 - T15),
         ConsDiff2 = abs(T15 - T25),
         ConsDiff3 = abs(T25 - T35),
         AllDiff1 = abs(T5 - T25),
         AllDiff2 = abs(T5 - T35),
         AllDiff3 = abs(T15 - T35)) %>% 
  rowwise() %>% 
  mutate(MaxConsDiff = max(ConsDiff1, ConsDiff2, ConsDiff3),
         MaxAllDiff = max(ConsDiff1, ConsDiff2, ConsDiff3, AllDiff1, AllDiff2, AllDiff3),
         Prop_rangeT = MaxConsDiff / MaxAllDiff) %>% 
  select(DateTime, Prop_rangeT)

# A tibble: 8 x 2
  DateTime            Prop_rangeT
  <dttm>                    <dbl>
1 2016-08-01 08:01:17       0.364
2 2016-08-01 09:17:14       0.357
3 2016-08-01 10:29:31       0.377
4 2016-08-01 11:35:02       0.417
5 2016-08-01 12:22:45       0.602
6 2016-08-01 13:19:27       0.520
7 2016-08-01 14:58:17       0.592
8 2016-08-01 15:30:10       0.583


0 commentaires

2
votes

Nous pouvons utiliser fuzzy_left_join

library(tidyverse)
library(fuzzyjoin)
df1 %>%
    fuzzy_left_join(
        df2 %>%
            gather(key, val, -DateTime) %>%
            group_by(DateTime) %>%
            arrange(DateTime) %>%
            summarise(ratio = max(abs(c(0, diff(val))) / max(abs(diff(combn(x, 2)))))),
        by = "DateTime", match_fun = list(`>`)) %>%
    group_by(DateTime.x) %>%
    filter(DateTime.x - DateTime.y == min(DateTime.x - DateTime.y))
## A tibble: 8 x 3
## Groups:   DateTime.x [8]
#  DateTime.x          DateTime.y          ratio
#  <dttm>              <dttm>              <dbl>
#1 2016-08-01 08:01:17 2016-08-01 08:00:00 0.364
#2 2016-08-01 09:17:14 2016-08-01 09:00:00 0.373
#3 2016-08-01 10:29:31 2016-08-01 10:00:00 0.364
#4 2016-08-01 11:35:02 2016-08-01 11:00:00 0.391
#5 2016-08-01 12:22:45 2016-08-01 12:00:00 0.591
#6 2016-08-01 13:19:27 2016-08-01 13:00:00 0.473
#7 2016-08-01 14:58:17 2016-08-01 14:00:00 0.527
#8 2016-08-01 15:30:10 2016-08-01 15:00:00 0.509

Explication: Nous remodelons df2 de large à long, et calculons le rapport maximal de (absolu ) différence de températures à des profondeurs consécutives et différence maximale de températures mesurées à toutes les profondeurs. Le reste est une jointure floue sur DateTime , où nous ne sélectionnons que les entrées les plus proches en date pour chaque DateHeure dans df1 . P >


0 commentaires

2
votes

Commencez par trouver les colonnes qui nous intéressent pour faire le calcul maximum (en commençant par "T"). Maintenant, pour chaque ligne de ces colonnes, calculez le rapport entre la différence maximale de la valeur consécutive et la différence maximale de la valeur totale. Faites correspondre l'horodatage dans df1 et df2 et obtenez le rapport correspondant.

t_cols <- grep("^T", names(df2))


df2$ratio <- apply(df2[t_cols], 1, function(x) {
       max_consecutive <- max(-diff(x))
       new_x <- sort(x)
       max_total <- new_x[length(x)] - new_x[1]
       max_consecutive/max_total
})


df1$Prop_rangeT <- df2$ratio[match(lubridate::floor_date(df1$DateTime, "hour"), 
                                                          df2$DateTime)]


df1
#             DateTime Prop_rangeT
#1 2016-08-01 08:01:17   0.3636364
#2 2016-08-01 09:17:14   0.3565217
#3 2016-08-01 10:29:31   0.3773585
#4 2016-08-01 11:35:02   0.4174757
#5 2016-08-01 12:22:45   0.6018519
#6 2016-08-01 13:19:27   0.5200000
#7 2016-08-01 14:58:17   0.5918367
#8 2016-08-01 15:30:10   0.5833333


0 commentaires

1
votes
#Assuming that df1 and df2 fit by row 
(df1$Prop_rangeT <- apply(df2[,2:5], 1, function(x) {max(abs(diff(x)))/diff(range(x))}))
#0.3636364 0.3565217 0.3773585 0.4174757 0.6018519 0.5200000 0.5918367 0.5833333

#In case they don't fit by row matching them e.g. by Year, Month, Day and Hour
df1$Prop_rangeT <- apply(df2[,2:5], 1, function(x) {
 max(abs(diff(x)))/diff(range(x))})[match(format(df1$DateTime, "%Y%m%d%H"), format(df2$DateTime, "%Y%m%d%H"))]

4 commentaires

Ils correspondent à cet exemple, mais cela ne convient généralement pas, donc j'aurais d'abord besoin de trouver la ligne dans df2 qui correspond à la ligne dans df1 concernant datetime.


J'ai mis à jour pour ce cas en utilisant l'année, le mois, le jour et l'heure comme date / heure pour la correspondance.


Merci beaucoup pour votre temps, mais cela n'a pas fonctionné! Quand je l'ai lancé, R a montré "Erreur: inesperado '}' dans" max (abs (diff (x))) / diff (range (x))} "


Vous devez utiliser les deux lignes non seulement celle commençant par max.