簡體   English   中英

R:通過匹配另一個 dataframe 的列,對 dataframe 中的值進行內插和外推

[英]R: Inter- and extrapolate values in dataframe by matching column of another dataframe

我有兩個數據框:

df1 <- data.frame(levels = c(1, 3, 5, 7, 9), 
                  values = c(2.2, 5.3, 7.9, 5.4, 8.7))

df2 <- data.frame(levels = c(1, 4, 8, 12)) # other columns not necessary

我希望根據 df1$levels 中的數字將 df1$values 內插到 df2$levels。 所以在第二個 dataframe 中有一些插值,但也外推到第 12 級。

也許,根據兩個數據集的levelsunion做一個complete的,然后使用na.approx (來自zoo )和rule = 2 (用於外推)

library(dplyr)
library(tidyr)
library(zoo)
df1 <- df1 %>% 
    complete(levels = union(levels, df2$levels)) %>%
    mutate(values = na.approx(values, maxgap = Inf, rule = 2))

-輸出

df1
# A tibble: 8 x 2
#  levels values
#   <dbl>  <dbl>
#1      1   2.2 
#2      3   5.3 
#3      4   6.6 
#4      5   7.9 
#5      7   5.4 
#6      8   7.05
#7      9   8.7 
#8     12   8.7 

我確信這可以被壓縮,這是我很久以前寫的一些代碼,它處理必須在有序向量的頭部/尾部進行外推:

# Function to interpolate / extrapolate: l_estimate => function()
l_estimate <- function(vec){
  # Function to perform-linear interpolation and return vector: 
  # .l_interp_vec => function()
  .l_interp_vec <- function(vec){
    interped_values <- 
      approx(x = vec, method = "linear", ties = "constant", n = length(vec))$y
    return(ifelse(is.na(vec), interped_values[is.na(vec)], vec))
  }
  
  # Store a vector denoting the indices of the vector that are NA: 
  # na_idx => integer vector
  na_idx <- is.na(vec)
  
  # Store a scalar of min row where x isn't NA: min_non_na => integer vector
  min_non_na <- min(which(!(na_idx)))
  
  # Store a scalar of max row where x isn't NA: max_non_na => integer vector
  max_non_na <- max(which(!(na_idx)))
  
  # Store scalar of the number of rows needed to impute prior 
  # to first NA value: ru_lower => integer vector
  ru_lower <- ifelse(min_non_na > 1, min_non_na - 1, min_non_na)
  
  # Store scalar of the number of rows needed to impute after
  # the last non-NA value: ru_upper => integer vector
  ru_upper <- ifelse(
    max_non_na == length(vec), 
    length(vec) - 1, 
    (length(vec) - (max_non_na + 1))
  )
  
  # Store a vector of the ramp to function: ramp_up => numeric vector 
  ramp_up <- as.numeric(
    cumsum(rep(vec[min_non_na]/(min_non_na), ru_lower))
  )
  
  # Apply the interpolation function on vector: y => numeric vector
  y <- as.numeric(.l_interp_vec(as.numeric(vec[min_non_na:max_non_na])))
  
  # Create a vector that combines the ramp_up vector 
  # and y if the first NA is at row 1:
  if(length(ramp_up) >= 1 & max_non_na != length(vec)){
    # Create a vector interpolations if there are 
    # multiple NA values after the last value: lower_l_int => numeric vector
    lower_l_int <- as.numeric(
      cumsum(rep(mean(diff(c(ramp_up, y))), ru_upper+1)) + 
        as.numeric(vec[max_non_na])
      )
    
    # Store the linear interpolations in  a vector: z => numeric vector
    z <- as.numeric(c(ramp_up, y, lower_l_int))
  
  }else if(length(ramp_up) > 1 & max_non_na == length(vec)){
    
    # Store the linear interpolations in  a vector: z => numeric
    z <- as.numeric(c(ramp_up, y))
    
  }else if(min_non_na == 1 & max_non_na != length(vec)){
    
    # Create a vector interpolations if there are 
    # multiple NA values after the last value: lower_l_int => numeric vector
    lower_l_int <- as.numeric(
      cumsum(rep(mean(diff(c(ramp_up, y))), ru_upper+1)) +
        as.numeric(vec[max_non_na])
      )
    
    # Store the linear interpolations in  a vector: z => numeric vector
    z <- as.numeric(c(y, lower_l_int))
    
  }else{
    # Store the linear interpolations in  a vector: z => numeric vector
    z <- as.numeric(y)
    
  }
  # Interpolate between points in x, return new x:
  return(as.numeric(ifelse(is.na(vec), z, vec)))
}

# Apply the function on ordered data: data.frame => stdout(console)
transform(full_df[order(full_df$levels),],
     values = l_estimate(values)
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM