簡體   English   中英

如何使用一組時間序列值的導數創建新列

[英]How to create a new column with the derivative of a set of time serie values

我正在尋求有關 R 的幫助。 我想將三列添加到包含時間序列數據並具有大量 NA 值的現有數據框中。 數據是關於考試成績的。 我要添加的第一列是可用的第一個測試分數。 在第二列中,我想要最后的測試分數。 在第三列中,我想通過將第一個和最后一個分數之間的差異除以已通過的測試數來計算每一行的導數。 重要的是這些過去的一些測試有 NA 值,但我仍然想在划分時包括這些值。 但是,我不想計算最后一個可用測試分數之后的 NA 值。

對我的數據的一些解釋: A 有幾個數據框,它們都有不同人的測試分數。 不同的人是行,每列代表一個測試分數。 對於數據框中的同一測試,每個人有多個測試分數。 T1 列顯示他們的第一個分數,T2 列顯示一周后收集的第二個分數,依此類推。 有些人比其他人開始得早,因此可以獲得更多的考試成績。 此外,由於各種原因,開頭和中間的一些分數缺失。 請參閱下面的兩個示例表,其中索引列是數據框的實際索引,而不是單獨的列。 索引中缺少一些數字(如 3),因為此人的行中只有 NA 值,我將其刪除。 索引保持這種狀態對我來說很重要。

示例 1(測試 A):

指數 T1 T2 T3 T4 T5 T6
1 不適用 不適用 不適用 3 4 5
2 57 57 57 57 不適用 不適用
4 44 不適用 不適用 不適用 不適用 不適用
5 9 11 11 17 12 不適用

示例 2(測試 B):

指數 T1 T2 T3 T4
1 不適用 不適用 不適用 17
2 11 16 20 20
4 1 20 不適用 不適用
5 20 20 20 20

我現在的目標是將前面提到的三列添加到這些數據框中。 例如 1 這看起來像:

指數 T1 T2 T3 T4 T5 T6 第一分數 最后得分 衍生物
1 不適用 不適用 不適用 3 4 5 3 5 0.33
2 57 57 57 57 不適用 不適用 57 57 0
4 44 不適用 不適用 不適用 不適用 不適用 44 44 0
5 9 11 11 17 12 不適用 9 12 0.6

例如2:

指數 T1 T2 T3 T4 第一分數 最后得分 衍生物
1 不適用 不適用 不適用 17 17 17 0
2 11 16 20 20 11 20 2.25
4 1 20 不適用 不適用 1 20 9.5
5 20 20 20 20 20 20 0

我希望我已經說清楚了,有人可以幫助我,在此先感謝!

你也可以這樣做:

df1 %>%
   rowwise()%>%
   mutate(firstScore = first(na.omit(c_across(T1:T6))),
          lastScore = last(na.omit(c_across(T1:T6))),
          Derivative = (lastScore-firstScore)/max(which(!is.na(c_across(T1:T6)))))

# A tibble: 4 x 10
# Rowwise: 
  INDEX    T1    T2    T3    T4    T5    T6 firstScore lastScore Derivative
  <int> <int> <int> <int> <int> <int> <int>      <int>     <int>      <dbl>
1     1    NA    NA    NA     3     4     5          3         5      0.333
2     2    57    57    57    57    NA    NA         57        57      0    
3     4    44    NA    NA    NA    NA    NA         44        44      0    
4     5     9    11    11    17    12    NA          9        12      0.6  

使用一個 pmap_*

pmap_dfr(df1, ~{c(...) %>% t %>% as.data.frame() %>% 
    mutate(first_score = first(na.omit(c(...)[-1])),
           last_score = last(na.omit(c(...)[-1])),
           deriv = (last_score - first_score)/max(which(!is.na(c(...)[-1]))))})

  INDEX T1 T2 T3 T4 T5 T6 first_score last_score     deriv
1     1 NA NA NA  3  4  5           3          5 0.3333333
2     2 57 57 57 57 NA NA          57         57 0.0000000
3     4 44 NA NA NA NA NA          44         44 0.0000000
4     5  9 11 11 17 12 NA           9         12 0.6000000

dplyr中,僅使用沒有cur_data rowwise()的 cur_data 會減慢操作速度

df1 %>% group_by(INDEX) %>%
  mutate(first_score = c_across(starts_with('T'))[min(which(!is.na(cur_data())))],
         last_score = c_across(starts_with('T'))[max(which(!is.na(cur_data()[1:6])))],
         deriv = (last_score - first_score)/max(which(!is.na(cur_data()[1:6]))))

我認為您可以使用以下解決方案。 令人驚訝的是,它有點冗長和令人費解,但我認為它非常有效。 我假設如果Last available score 實際上不是最后一個T ,那么我需要檢測它的索引並將差異除以它,這意味着最后一個之后的NA值不計算在內。 否則,它除以所有可用T的數量。

library(dplyr)
library(purrr)

df %>%
  select(T1:T6) %>%
  pmap(., ~ {x <- c(...)[!is.na(c(...))]; c(x[1], x[length(x)])}) %>%
  exec(rbind, !!!.) %>%
  as_tibble() %>%
  set_names(c("First", "Last")) %>%
  bind_cols(df) %>%
  relocate(First, Last, .after = last_col()) %>%
  rowwise() %>%
  mutate(Derivative = ifelse(!is.na(T6) & T6 == Last, (Last - First)/(length(df)-1), 
                             (Last - First)/last(which(c_across(T1:T6) == Last))))


# First Sample Data
# A tibble: 4 x 10
# Rowwise: 
  INDEX    T1    T2    T3    T4    T5    T6 First  Last Derivative
  <int> <int> <int> <int> <int> <int> <int> <int> <int>      <dbl>
1     1    NA    NA    NA     3     4     5     3     5      0.333
2     2    57    57    57    57    NA    NA    57    57      0    
3     4    44    NA    NA    NA    NA    NA    44    44      0    
4     5     9    11    11    17    12    NA     9    12      0.6  

第二個樣本數據

df2 %>%
  select(T1:T4) %>%
  pmap(., ~ {x <- c(...)[!is.na(c(...))]; c(x[1], x[length(x)])}) %>%
  exec(rbind, !!!.) %>%
  as_tibble() %>%
  set_names(c("First", "Last")) %>%
  bind_cols(df2) %>%
  relocate(First, Last, .after = last_col()) %>%
  rowwise() %>%
  mutate(Derivative = ifelse(!is.na(T4) & T4 == Last, (Last - First)/(length(df2)-1), 
                             (Last - First)/last(which(c_across(T1:T4) == Last))))

# A tibble: 4 x 8
# Rowwise: 
  INDEX    T1    T2    T3    T4 First  Last Derivative
  <int> <int> <int> <int> <int> <int> <int>      <dbl>
1     1    NA    NA    NA    17    17    17       0   
2     2    11    16    20    20    11    20       2.25
3     4     1    20    NA    NA     1    20       9.5 
4     5    20    20    20    20    20    20       0  

這是一個沒有硬編碼的 tidyverse 解決方案。 首先我 pivot 更長,然后提取每個 INDEX 的統計數據。

library(tidyverse)
df1 %>%
  pivot_longer(-INDEX, names_to = "time", names_prefix = "T", names_transform = list(time = as.integer)) %>%
  filter(!is.na(value)) %>%
  group_by(INDEX) %>%
  summarize(FirstScore = first(value), LastScore = last(value), divisor = max(time)) %>%
  mutate(Derivative = (LastScore - FirstScore) / divisor) %>%
  right_join(df1) %>%
  select(INDEX, T1:T6, FirstScore, LastScore, Derivative)

對於這個 output:

# A tibble: 4 x 10
  INDEX    T1    T2    T3    T4    T5    T6 FirstScore LastScore Derivative
  <int> <int> <int> <int> <int> <int> <int>      <int>     <int>      <dbl>
1     1    NA    NA    NA     3     4     5          3         5      0.333
2     2    57    57    57    57    NA    NA         57        57      0    
3     4    44    NA    NA    NA    NA    NA         44        44      0    
4     5     9    11    11    17    12    NA          9        12      0.6  

Output 用於第二個數據,代碼不變:

# A tibble: 4 x 10
  INDEX    T1    T2    T3    T4    T5    T6 FirstScore LastScore Derivative
  <int> <int> <int> <int> <int> <int> <int>      <int>     <int>      <dbl>
1     1    NA    NA    NA     3     4     5         17        17       0   
2     2    57    57    57    57    NA    NA         11        20       2.25
3     4    44    NA    NA    NA    NA    NA          1        20       9.5 
4     5     9    11    11    17    12    NA         20        20       0   

樣本數據

df1 <- data.frame(
       INDEX = c(1L, 2L, 4L, 5L),
          T1 = c(NA, 57L, 44L, 9L),
          T2 = c(NA, 57L, NA, 11L),
          T3 = c(NA, 57L, NA, 11L),
          T4 = c(3L, 57L, NA, 17L),
          T5 = c(4L, NA, NA, 12L),
          T6 = c(5L, NA, NA, NA)
)

df2 <- data.frame(
       INDEX = c(1L, 2L, 4L, 5L),
          T1 = c(NA, 11L, 1L, 20L),
          T2 = c(NA, 16L, 20L, 20L),
          T3 = c(NA, 20L, NA, 20L),
          T4 = c(17L, 20L, NA, 20L)
       )

暫無
暫無

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

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