簡體   English   中英

改變一個因素的一個水平后一個水平

[英]Change a level of a factor after another level

我想改變一個因素的水平順序,以便一個特定的水平緊跟在另一個水平之后,但我正在努力如何有效地做到這一點。

假設我們想改變以下因子的水平,使“20”緊跟在“10”之后。 所以我嘗試了這個並成功地得到了預期的結果:

library(tidyverse)

sample_factor <- factor(1:30)

trial_factor1 <- sample_factor %>% fct_relevel("20", after=which(levels(.)=="10"))
levels(trial_factor1)
#>  [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "20" "11" "12" "13" "14"
#> [16] "15" "16" "17" "18" "19" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30"

但是,如果將初始因子的順序顛倒,則不起作用:

trial_factor2 <- sample_factor %>% fct_rev() %>% fct_relevel("20", after=which(levels(.)=="10"))
levels(trial_factor2)
#>  [1] "30" "29" "28" "27" "26" "25" "24" "23" "22" "21" "19" "18" "17" "16" "15"
#> [16] "14" "13" "12" "11" "10" "9"  "20" "8"  "7"  "6"  "5"  "4"  "3"  "2"  "1"

這可能是因為在這種情況下,“20”最初位於“10”之前。

此外,如果我還嘗試更改順序,使“30”緊隨“20”之后(預期因子水平:...、10、20、30、...),結果會變得更糟:

trial_factor3 <- sample_factor %>% fct_rev() %>% fct_relevel("20", after=which(levels(.)=="10")) %>%
  fct_relevel("30", after=which(levels(.)=="20"))
levels(trial_factor3)
#>  [1] "29" "28" "27" "26" "25" "24" "23" "22" "21" "19" "18" "17" "16" "15" "14"
#> [16] "13" "12" "11" "10" "9"  "20" "8"  "30" "7"  "6"  "5"  "4"  "3"  "2"  "1"

reprex package (v2.0.1) 於 2022 年 8 月 18 日創建

在我的實際情況下,我想多次(超過5次)改變水平的順序,我並不清楚因素水平的初始順序,所以我發現靈活改變順序真的很困難。

非常感謝您提前提供的幫助!

問題是after參數指定 position 將級別放置在最終output 中,而使用after = which(levels(.) == "10")您正在根據當前Z4757FE07FD492A8BEDEEZA6 的目標確定after . 因此,如果您從訂單的前面刪除它,那么您對目標位置的描述需要相應地調整。 如果它是從目的地之后的某個地方移動的,那很好。 因此,對於您的應用程序,我認為您需要測試您有哪些情況。 這是一個小幫手 function 來測試並返回適當定位的重新調平。

注意:如果您要一次移動多個級別,則必須使 function 更加復雜,以測試從目的地之前有多少級別並相應地進行調整。

library(tidyverse)

f <- factor(1:5)

# works because nothing is removed from before the "after" position
f %>% fct_relevel("5", after = which(levels(.) == "3")) %>% levels()
#> [1] "1" "2" "3" "5" "4"

# fails because you are removing one element from before the "after" position
# so the new location should be shifted by 1
f %>% fct_relevel("3", after = which(levels(.) == "4")) %>% levels()
#> [1] "1" "2" "4" "5" "3"

# this function tests if the moves comes from before or after destination
fct_relevel_after <- function(fct, lev, after){
  l <- levels(fct)
  a <- match(lev, l)
  b <- match(after, l)
  if(a < b) {
    return(fct_relevel(fct, lev, after = b-1))
  } else {
    return(fct_relevel(fct, lev, after = b))
  }
}

# both work as desired
f %>% fct_relevel_after("5", "3") %>% levels()
#> [1] "1" "2" "3" "5" "4"
f %>% fct_relevel_after("3", "4") %>% levels()
#> [1] "1" "2" "4" "3" "5"

代表 package (v2.0.1) 於 2022 年 8 月 17 日創建

似乎fct_relevel旨在按位置工作,將此級別設為第 n 級(其中n = after + 1 ... 有點奇怪的設計/命名決定),但您只想根據級別名稱(標簽)工作。

我們可以編寫自己的版本來執行此操作,將label轉換為position ,並解決標簽前后的問題。 (另外,為什么在一個樣本中使用 30 個級別,而 5 個級別會很好呢?)

fct_relevel_label = function(.f, level, after_label) {
  lev = levels(.f)
  move = which(lev == level)
  target = which(lev == after_label)
  after = if(move <= target) {target - 1} else {target}
  fct_relevel(.f, level, after = after)
}

factor(1:5) %>% fct_relevel_label("2", after_label = "4") %>% levels
# [1] "1" "3" "4" "2" "5"

factor(1:5) %>% fct_rev() %>% fct_relevel_label("2", after_label = "4") %>% levels
# [1] "5" "4" "2" "3" "1"

暫無
暫無

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

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