[英]Manipulating a column based on other column values with R dplyr package
我想為每個學生選擇最好的 2 個測驗考試結果(最高分和最高出勤率),並消除 3 個測驗考試中最弱的測驗。 我們可能會說,我想從每行的 3 列中選擇最好的 2 列。 然后創建一個包含StudentID, ExamQuiz1, ExamQuiz2, ExamMidterm and ExamFinal
的新數據框。 我可以通過循環遍歷表格來處理它,這在 R 中效率太低我假設。 處理 dplyr package 問題的有效方法是什么?
極簡數據
偽數據框放置在底部。 “ G
”表示學生沒有參加考試,所以我想保留該值而不是將其替換為 0。例如,如果他使用 G ( ExamQuiz1
)、0 ( ExamQuiz2
)、10 ( ExamQuiz3
) 得到這個場景,我必須選擇 0 作為ExamQuiz1
和 10 作為ExamQuiz2
用於測驗輸入。 因為出勤方面0比G
好。 如果有結果(帶數字),則表示學生已經參加。 ExamQuiz1, ExamQuiz2, ExamMidterm and ExamFinal
列下的每個單元格都可能具有數字(考試結果)或字符值(“ G
”> 未參加)。 我不會觸及 ExamMidterm 和 ExamFinal 列的任何值。 主要思想僅與ExamQuiz1, ExamQuiz2, and ExamQuiz3
的列相關。
StudentID ExamQuiz1 ExamQuiz2 ExamQuiz3 ExamMidterm ExamFinal
1 11111 0 G G G G
2 22222 0 G 43 71 18
3 33333 0 G G G G
4 44444 0 G G G G
5 55555 60 38 G 64 27
6 66666 0 G G G G
編輯:仍然有一些評論者不斷指出數據不整潔。 正如我在評論中解釋的那樣,這樣做的原因或您提供的整理方法對我來說沒有意義。 出於這個原因,我在問題主體上放置了更多的解釋,而不改變數據的結構。
一基R解決方案
cbind(df[-(2:4)], t(apply(df[2:4], 1, function(x){
c(x[x == "G"], sort(x[x != "G"]))[-1]
})))
# StudentID Midterm Final 1 2
# 1 11111 G G G 0
# 2 22222 71 18 0 43
# 3 33333 G G G 0
# 4 44444 G G G 0
# 5 55555 64 27 38 60
# 6 66666 G G G 0
在您的規則中,應將G
放在任何數字前面。 所以起初我把所有現有的G
放在一個向量的開頭,然后 append 排序分數。 刪除向量中的第一個元素后,將保留前 2 個分數。
這是dplyr
across
新方法(版本1.0.0
或更高版本):
假設沒有人可以得到負分並且缺席比得到零更糟糕,我們可以將G
設置為-1
。
library(dplyr)
data %>%
mutate(across(-StudentID, ~case_when(. == "G" ~ -1,
TRUE ~ as.numeric(.)))) %>%
rowwise() %>%
mutate(TopQuiz = max(c_across(starts_with("Quiz"))),
SecondQuiz = sort(c_across(starts_with("Quiz")),
decreasing = TRUE)[2]) %>%
dplyr::select(StudentID, TopQuiz, SecondQuiz, Midterm, Final) %>%
mutate(across(-StudentID, ~case_when(. == -1 ~ "G",
TRUE ~ as.character(.))))
##A tibble: 6 x 5
## Rowwise:
# StudentID TopQuiz SecondQuiz Midterm Final
# <int> <chr> <chr> <chr> <chr>
#1 11111 0 G G G
#2 22222 43 0 71 18
#3 33333 0 G G G
#4 44444 0 G G G
#5 55555 60 38 64 27
#6 66666 0 G G G
應用dplyr
和stringr
的方式略有不同,方法是讓 G NA 進行數學運算,然后將 NA 放回 G 並返回字符。
library(dplyr)
library(stringr)
newgrades <- grades %>%
mutate(across(starts_with("Quiz"), ~ str_replace(., "G", NA_character_))) %>%
mutate(across(starts_with("Quiz"), as.numeric)) %>%
rowwise() %>%
mutate(TopQuiz = max(c_across(starts_with("Quiz")), na.rm = TRUE),
NextBestQuiz = sort(c_across(starts_with("Quiz")),
decreasing = TRUE)[2]) %>%
mutate(across(ends_with("Quiz"), as.character)) %>%
mutate(across(ends_with("Quiz"), ~ str_replace_na(., replacement = "G"))) %>%
select(id, TopQuiz, NextBestQuiz, Midterm, Final)
newgrades
#> # A tibble: 6 x 5
#> # Rowwise:
#> id TopQuiz NextBestQuiz Midterm Final
#> <int> <chr> <chr> <chr> <chr>
#> 1 1 0 G G G
#> 2 2 43 0 71 18
#> 3 3 0 G G G
#> 4 4 0 G G G
#> 5 5 60 38 64 27
#> 6 6 0 G G G
您的數據
grades <- data.frame(
id = c(1:6),
Quiz1 = c("0","0","0","0","60","0"),
Quiz2 = c("G","G","G","G","38","G"),
Quiz3 = c("G","43","G","G","G","G"),
Midterm = c("G","71","G","G","64","G"),
Final = c("G","18","G","G","27","G")
)
`
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.