Как добавить новый столбец в df1, который представляет собой интерполяцию на основе интервалов между двумя последовательными столбцами df2 (df2 $ `5`, df2 $` 15`, df2 $ `25`, df2 $` 35`) - PullRequest
0 голосов
/ 01 апреля 2019

Я хочу добавить новый столбец T в df1, который зависит от отношения между df1$x и df2. Чтобы вы это хорошо понимали, df1$x - это глубина рыбы, а разные столбцы df2$T - это температура воды на разных глубинах (5, 15, 25 и 35 метров). Я хочу оценить в df1$T температуру воды, в которой рыба находилась в зависимости от температуры воды в колонне. Как пример:

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"), x = c(NA,27,44,33,15,17,22,35))
df1$DateTime<- as.POSIXct(df1$DateTime, format = "%Y-%m-%d %H:%M:%S", tz= "UTC") 
df1$DateTime1<- strptime(df1$DateTime, "%Y-%m-%d %H",tz= "UTC") # I create a DateTime variable in the same format than in `df2`.
df1$DateTime1<- as.POSIXct(df1$DateTime1, format = "%Y-%m-%d %H", tz= "UTC") # I transform it to POSIXct.
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         x           DateTime1
1 2016-08-01 08:01:17        NA 2016-08-01 08:00:00
2 2016-08-01 09:17:14        27 2016-08-01 09:00:00
3 2016-08-01 10:29:31        44 2016-08-01 10:00:00
4 2016-08-01 11:35:02        33 2016-08-01 11:00:00
5 2016-08-01 12:22:45        15 2016-08-01 12:00:00
6 2016-08-01 13:19:27        17 2016-08-01 13:00:00
7 2016-08-01 14:58:17        22 2016-08-01 14:00:00
8 2016-08-01 15:30:10        35 2016-08-01 15:00:00

df2
             DateTime   T5  T15  T25  T35
1 2016-08-01 08:00:00 27.0 23.0 19.0 16.0 # No difference bigger than 5 at any interval (neither T5 and T15, nor T15 and T25 nor T25 and T35).
2 2016-08-01 09:00:00 27.5 23.4 20.0 16.0 # No difference bigger than 5 at any interval (neither T5 and T15, nor T15 and T25 nor T25 and T35).
3 2016-08-01 10:00:00 27.1 23.1 19.5 16.5 # No difference bigger than 5 at any interval (neither T5 and T15, nor T15 and T25 nor T25 and T35).
4 2016-08-01 11:00:00 27.0 22.7 19.6 16.7 # No difference bigger than 5 at any interval (neither T5 and T15, nor T15 and T25 nor T25 and T35).
5 2016-08-01 12:00:00 26.8 22.5 16.0 16.3 # A difference greater than 5 between `df2$T15` and `df2$25`.
6 2016-08-01 13:00:00 26.3 21.5 16.3 16.7 # A difference greater than 5 between `df2$T15` and `df2$25`.
7 2016-08-01 14:00:00 26.0 22.0 16.2 16.9 # A difference greater than 5 between `df2$T15` and `df2$25`.
8 2016-08-01 15:00:00 26.3 22.3 16.7 16.7 # A difference greater than 5 between `df2$T15` and `df2$25`.

Я хочу следующее:

Когда df1$x (глубина моей рыбы) ниже, чем df$T5, я хочу, чтобы df1$x было df2$T5. Когда df1$x (глубина моей рыбы) больше, чем df$T35, я хочу, чтобы df1$x был df2$T35. Если глубина моей рыбы df1$x составляет от 5 до 35, посмотрите, в каком интервале (T5 и T15, T15 и T25, T25 и T35) и:

  • Если разница между концами интервала меньше 5, то df1$x является интерполяцией между значениями в концах интервала.

  • Если разница между концами интервала больше 5, разделите интервал пополам. В верхней половине (например, между df$T5 и df$T10) интерполируйте df1$x, предполагая df2$10 == df2$T15. В нижней половине (от df2$T10 до df2$T15) df1$x == df2$T15.

Результат, который я ожидаю, будет:

result
             DateTime         x           DateTime1      T
1 2016-08-01 08:01:17        NA 2016-08-01 08:00:00     NA
2 2016-08-01 09:17:14        27 2016-08-01 09:00:00  19.20
3 2016-08-01 10:29:31        44 2016-08-01 10:00:00  16.50
4 2016-08-01 11:35:02        33 2016-08-01 11:00:00  17.28
5 2016-08-01 12:22:45        15 2016-08-01 12:00:00  22.50
6 2016-08-01 13:19:27        17 2016-08-01 13:00:00  19.42
7 2016-08-01 14:58:17        22 2016-08-01 14:00:00  16.20
8 2016-08-01 15:30:10        35 2016-08-01 15:00:00  16.70

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

y <- seq(from=5, to=15, by=1) # I create a vector with 11 levels. The upper level corresponds to the above water temperature sensor `df2$T5` and the last level to the below sensor `df2$T15´.
y[2:10]<- "NA" # We don't know water temperature at the levels between the upper and last one. We either interpolate them or assume that they are equal to the water temperature at the lower level.
y<- as.numeric(y)
y
x <- seq(from=15, to=25, by=1) # The same criteria. In this case, the vector is for x when `df1$x` is between 15 and 25.
x[2:10]<- "NA"
x<- as.numeric(x)
x
k <- seq(from=25, to=35, by=1) # The same criteria. In this case, the vector is for x when `df1$x` is between 25 and 35.
k[2:10]<- "NA"
k<- as.numeric(k)
k

for (i in 1:nrow(df1)) {
  if (is.na(df1$x[i])){
    df1$T[i] <-"NA"
  }else if (!is.na(df1$x[i]) & df1$x[i] > 0 & df1$x[i] <= 5){
    df1$T[i] <- df2$T5[which(df1$DateTime1[i] == df2$DateTime)]
  }else if (!is.na(df1$x[i]) & df1$x[i] > 5 & df1$x[i] <= 15 & df2$T15[which(df1$DateTime1[i] == df2$DateTime)] - df2$T5[which(df1$DateTime1[i] == df2$DateTime)] < 5){
    y[1]<- df2$T5[which(df1$DateTime1[i] == df2$DateTime)]
    y[11]<- df2$T15[which(df1$DateTime1[i] == df2$DateTime)]
    y <-na.approx(y)
    df1$T[i] <- y[round(df1$x[i])-4]
    y <- seq(from=5, to=15, by=1)
    y[2:10]<- "NA"
    y<- as.numeric(y)
  }else if (!is.na(df1$x[i]) & df1$x[i] > 15 & df1$x[i] <= 25 & df2$T25[which(df1$DateTime1[i] == df2$DateTime)] - df2$T15[which(df1$DateTime1[i] == df2$DateTime)] < 5){
    x[1]<- df2$T15[which(df1$DateTime1[i] == df2$DateTime)]
    x[11]<- df2$T25[which(df1$DateTime1[i] == df2$DateTime)]
    x <-na.approx(x)
    df1$T[i] <- x[round(df1$x[i])-14]
    x <- seq(from=15, to=25, by=1)
    x[2:10]<- "NA"
    x<- as.numeric(x)
  }else if (!is.na(df1$x[i]) & df1$x[i] > 25 & df1$x[i] <= 35 & df2$T35[which(df1$DateTime1[i] == df2$DateTime)] - df2$T25[which(df1$DateTime1[i] == df2$DateTime)] < 5){
    k[1]<- df2$T25[which(df1$DateTime1[i] == df2$DateTime)]
    k[11]<- df2$T35[which(df1$DateTime1[i] == df2$DateTime)]
    k <-na.approx(k)
    df1$T[i] <- k[round(df1$x[i])-24]
    k <- seq(from=25, to=35, by=1)
    k[2:10]<- "NA"
    k<- as.numeric(k)
  }else if (!is.na(df1$x[i]) & df1$x[i] > 5 & df1$x[i] <= 15 & df2$T15[which(df1$DateTime1[i] == df2$DateTime)] - df2$T5[which(df1$DateTime1[i] == df2$DateTime)] > 5){
    y[1]<- df2$T5[which(df1$DateTime1[i] == df2$DateTime)]
    y[6]<- df2$T15[which(df1$DateTime1[i] == df2$DateTime)]
    y[11]<- df2$T15[which(df1$DateTime1[i] == df2$DateTime)]
    y <-na.approx(y)
    df1$T[i] <- y[round(df1$x[i])-4]
    y <- seq(from=5, to=15, by=1)
    y[2:10]<- "NA"
    y<- as.numeric(y)
  }else if (!is.na(df1$x[i]) & df1$x[i] > 15 & df1$x[i] <= 25 & df2$T25[which(df1$DateTime1[i] == df2$DateTime)] - df2$T15[which(df1$DateTime1[i] == df2$DateTime)] > 5){
    x[1]<- df2$T15[which(df1$DateTime1[i] == df2$DateTime)]
    x[6]<- df2$T25[which(df1$DateTime1[i] == df2$DateTime)]
    x[11]<- df2$T25[which(df1$DateTime1[i] == df2$DateTime)]
    x <-na.approx(x)
    df1$T[i] <- x[round(df1$x[i])-14]
    x <- seq(from=15, to=25, by=1)
    x[2:10]<- "NA"
    x<- as.numeric(x)
  }else if (!is.na(df1$x[i]) & df1$x[i] > 25 & df1$x[i] <= 35 & df2$T35[which(df1$DateTime1[i] == df2$DateTime)] - df2$T25[which(df1$DateTime1[i] == df2$DateTime)] > 5){
    k[1]<- df2$T25[which(df1$DateTime1[i] == df2$DateTime)]
    k[6]<- df2$T35[which(df1$DateTime1[i] == df2$DateTime)]
    k[11]<- df2$T35[which(df1$DateTime1[i] == df2$DateTime)]
    k <-na.approx(k)
    df1$T[i] <- k[round(df1$x[i])-24]
    k <- seq(from=25, to=35, by=1)
    k[2:10]<- "NA"
    k<- as.numeric(k) 
  }else if (!is.na(df1$x[i]) & df1$x[i] > 35){
    df1$T[i] <- df2$T35[which(df1$DateTime1[i] == df2$DateTime)]
  }
}

1 Ответ

1 голос
/ 01 апреля 2019
#Assuming that df1 and df2 fit by row (If not you might need to use merge)
#Simple interpolation (don't care of tdif >= 5)
df1$T <- sapply(1:NROW(df1), function(x) approxfun(c(5,15,25,35), df2[x,c("T5","T15","T25","T35")], rule=2)(df1$x[x]))

#Using you rules (can reproduce your expected result)
#And merging by df1$DateTime1 and df2$DateTime
df1$T <- sapply(1:NROW(df1), function(x) {
  depth <- df1$x[x]
  if(!is.finite(depth)) {return(NA);}
  dc <- c(5,15,25,35)
  temp <- as.numeric(df2[match(df1$DateTime1[x], df2$DateTime)[1],c("T5","T15","T25","T35")])
  idx0 <- findInterval(depth, c(15,25,35))+1
  idx1 <- findInterval(depth, c(5,15,25))+1
  tDif <- abs(temp[idx1] - temp[idx0])
  if(tDif<5) {return(temp[idx0] + (depth - dc[idx0]) * (temp[idx1] - temp[idx0]) / 10)}
  if(depth%%10 >=5) {return(temp[idx0] + 2*(depth - dc[idx0]) * (temp[idx1] - temp[idx0]) / 10)}
  temp[idx1]
}
)
#NA 19.20 16.50 17.28 22.50 19.42 16.20 16.70
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...