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
4 Réponses :
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
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 >
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
#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"))]
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.