簡體   English   中英

dplyr 創建一個具有復雜用戶定義的新列 function 的其他列

[英]dplyr create a new column with a complex user defined function of other columns

我有一個包含 40 個問題(下面有 3 個問題的代表)的大型數據框,需要計算一個新列,它是這 40 個響應的復雜 function。 由於幾乎不可能在mutate中寫出 function ,因此我嘗試創建一個可以在mutate中使用的 function f

df <- data.frame(Sex = c(rep("F", 5), rep("M", 5)),
                 Q1  = sample(0:10, 10, replace=T),
                 Q2  = sample(0:10, 10, replace=T),
                 Q3  = sample(0:10, 10, replace=T)
)

f <- function(q1, q2, q3){
  y <- q1 + (q2^2) - (q3^3)
  return(y)
} 

現在使用mutate創建一個新列可以正常工作。:

df %>%
   mutate(newcol = f(Q1, Q2, Q3))

  Sex Q1 Q2 Q3 newcol
1    F 10  6  3     19
2    F  0  9  9   -648
3    F  8  1  2      1
4    F  0  4  7   -327
5    F  6  4  1     21
6    M  8  3  3    -10
7    M  2  2  0      6
8    M 10  0  3    -17
9    M  6  9  3     60
10   M  1  7  2     42

一樣

 df$newcol <- mapply(f, df$Q1, df$Q2, df$Q3)

但是,如果我在f中包含一個簡單的if atatement,如下所示

f <- function(q1, q2, q3){
  y <- q1 + (q2^2) - (q3^3)
  if(y<0){
    y <- -y
  }
  return(y)
} 

我的手上立刻就有了災難:

df %>%
+   mutate(newcol = f(Q1, Q2, Q3))
   Sex Q1 Q2 Q3 newcol
1    F 10  6  3     19
2    F  0  9  9   -648
3    F  8  1  2      1
4    F  0  4  7   -327
5    F  6  4  1     21
6    M  8  3  3    -10
7    M  2  2  0      6
8    M 10  0  3    -17
9    M  6  9  3     60
10   M  1  7  2     42
Warning message:
Problem with `mutate()` input `newcol`.
i the condition has length > 1 and only the first element will be used
i Input `newcol` is `f(Q1, Q2, Q3)`. 

然而,

df$newcol <- mapply(f, df$Q1, df$Q2, df$Q3)
df
   Sex Q1 Q2 Q3 newcol
1    F 10  6  3     19
2    F  0  9  9    648
3    F  8  1  2      1
4    F  0  4  7    327
5    F  6  4  1     21
6    M  8  3  3     10
7    M  2  2  0      6
8    M 10  0  3     17
9    M  6  9  3     60
10   M  1  7  2     42

繼續工作。 不幸的是,我的 function 中有很多 if,並且有 40 種不同的 arguments 傳遞給 function,mapply 的輸入變得巨大。 如何使用預定義的向量將我的問題傳遞給 mapply,比如

questions <- c("df$Q1", "df$Q2", "df$Q3") 
df$newcol <- mapply(f, questions)

密切相關:如何定義一個 function 和 40 arguments 而不會跑出頁面?

我完全有可能找錯了樹,如果是這樣,我應該如何解決我的問題?

提前謝謝了

托馬斯飛利浦

PS這是真正的標准

if(!is.na(df[i, "Q1_Daily_Mean"]) & df[i, "Q1_Daily_Mean"] >= THRESHOLD_MDD_GAD){
  anxiety <- TRUE
}

if(!is.na(df[i, "Q2_Daily_Mean"]) & df[i, "Q2_Daily_Mean"] >= THRESHOLD_MDD_GAD){
  worry <- TRUE
}

if(anxiety && worry){
  anxiety_and_worry <- TRUE
}

if(!is.na(df[i, "Q3_Daily_Mean"]) & df[i, "Q3_Daily_Mean"] >= THRESHOLD_MDD_GAD ){
  agitation <- TRUE
}

if(!is.na(df[i, "Q10_Daily_Mean"]) & df[i, "Q10_Daily_Mean"] >= THRESHOLD_MDD_GAD ){
  anger <- TRUE
}

if(!is.na(df[i, "Q2_Weekly"]) & df[i, "Q2_Weekly"] >= THRESHOLD_MDD_GAD ){
  physical_fatigue <- TRUE
}

if(!is.na(df[i, "Q5_Weekly"]) & df[i, "Q5_Weekly"] >= THRESHOLD_MDD_GAD ){
  no_concentration <- TRUE
}

if(!is.na(df[i, "Q7_Weekly"]) & df[i, "Q7_Weekly"] >= THRESHOLD_MDD_GAD ){
  disturbed_sleep <- TRUE
}

if(!is.na(df[i, "Q13_Weekly"]) & !is.na(df[i, "Q14_Weekly"]) &
   !is.na(df[i, "Q15_Weekly"]) & !is.na(df[i, "Q16_Weekly"]) & 
   !is.na(df[i, "Q17_Weekly"]) & 
   max( df[i, "Q13_Weekly"], df[i, "Q14_Weekly"],
        df[i, "Q15_Weekly"], df[i, "Q16_Weekly"],
        df[i, "Q17_Weekly"] ) >= THRESHOLD_MDD_GAD){
  max_function  <- TRUE
}

sum_of_symptoms_7 <- anxiety + worry + agitation + anger + 
                     physical_fatigue + no_concentration + disturbed_sleep

if (anxiety_and_worry && (sum_of_symptoms_7 >= CRITERIA_NEEDED_GAD) && max_function){
  # Generalized Anxiety Disorder
  df[i, GAD_DESCRIPTPR_EML] <- TRUE
}

基本上,帶有if語句的 function 沒有向量化。 你有兩個選擇。

  1. 使 function 矢量化(使用ifelse或任何其他方式)並像之前一樣繼續使用mutate
library(dplyr)
library(purrr)

df %>% mutate(newcol = f(Q1, Q2, Q3))
  1. 如果條件太復雜並且您無法對 function 進行矢量化,請使用rowwisepmap一次操作一行。 這類似於您的mapply嘗試。
df %>% mutate(newcol = pmap_dbl(list(Q1, Q2, Q3), ~f(..1, ..2, ..3)))

您收到“條件長度 > 1 且僅使用第一個元素”警告的原因是if與向量結合使用(例如,請參見此處)。 dpylrmutate將值的“整個”向量傳遞給被調用的 function,(即不是逐個元素的(行)元素)。 這就是if語句被混淆的地方。

這解決了你的問題:

df <- data.frame(Sex = c(rep("F", 5), rep("M", 5)),
                 Q1  = sample(0:10, 10, replace=T),
                 Q2  = sample(0:10, 10, replace=T),
                 Q3  = sample(0:10, 10, replace=T)
)

f <- function(q1, q2, q3){
  y <- q1 + (q2^2) - (q3^3)
  y <- ifelse(y<0, -y, y)
  return(y)
} 

df %>%
  mutate(newcol = f(Q1, Q2, Q3))

回報:

 Sex Q1 Q2 Q3 newcol 1 F 8 6 3 17 2 F 6 0 0 6 3 F 4 5 7 314 4 F 9 5 7 309 5 F 3 5 9 701 6 M 1 10 5 24 7 M 10 5 4 29 8 M 4 0 3 23 9 M 8 4 7 319 10 M 3 6 3 12

要擴展我上面的評論:

f <- function(data, conditions) {
  columnNames <- names(conditions)
  for (colName in columnNames) {
    qName <- enquo(colName)
    data <- data %>% mutate(!!qName := eval(conditions[[colName]]))
  }
  data
}

df %>% f(list(bigQ1=expression(Q1 > 7), smallQ2=expression(Q2 < 2)))

給出,例如,

   Sex Q1 Q2 Q3 bigQ1 smallQ2
1    F  2  9  9 FALSE   FALSE
2    F  2 10  6 FALSE   FALSE
3    F  9  4  9  TRUE   FALSE
4    F  1  2  8 FALSE   FALSE
5    F  5 10  2 FALSE   FALSE
6    M 10  8  3  TRUE   FALSE
7    M  4  8  0 FALSE   FALSE
8    M  3  8 10 FALSE   FALSE
9    M  5  2  6 FALSE   FALSE
10   M  8  7  4  TRUE   FALSE

傳遞 df 作為 function 的第一個參數允許管道。

暫無
暫無

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

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