簡體   English   中英

R:使用數據表重新排序因子級別(用於Plotly)

[英]R: Reorder factor levels with data table (for use with Plotly)

TL;博士

是否可以通過引用重新排序數據表中列的因子級別? 據我所知,不是現有的答案:

  • 這是有效的,但不是通過引用( 鏈接 ): table$x <- factor(table$x, levels = c("giraffes", "orangutans", "monkeys"))
  • 這通過引用工作,但對表的其他列( 鏈接 )有意想不到的影響: setattr(mydt$value,"levels",c(...))

接受的答案提供了一種無副作用的方法,使用:=表示法。

該問題的背景是需要重新排序Plotly中的條形圖,該條形圖規定了重新排序因子水平( 鏈接 )。


原始問題

我需要重新排序數據表框架中列的因子級別,我想以原生數據表的方式進行,如果有的話。 我知道我可以用數據幀方式來做,但這需要硬編碼的列名。 我想使用動態列名,如果可能的話,通過引用更新。 我找到了一種通過引用( 鏈接 )重新排序列的方法,但它沒有相應地重新排序其他列,也無法使用動態列引用。

我有以下數據(人均二氧化碳排放量):

library(data.table)
print(data)
        indicator        country year     value
1: EN.ATM.CO2E.PC         Canada 2011 15.639760
2: EN.ATM.CO2E.PC          China 2011  7.241515
3: EN.ATM.CO2E.PC European Union 2011  7.079374
4: EN.ATM.CO2E.PC          India 2011  1.476686
5: EN.ATM.CO2E.PC   Saudi Arabia 2011 17.702307
6: EN.ATM.CO2E.PC  United States 2011 16.972417

class(data)
[1] "data.table" "data.frame"

print(str(lapply(data, class)))
List of 8
 $ indicator     : chr "factor"
 $ country       : chr "factor"
 $ year          : chr "factor"
 $ value         : chr "numeric"

因此,如果我想按國家/地區列反向排序,我可以這樣做( 2 ):

col <- "country"
column.levels <- levels(data[[col]])
column.levels <- sort(column.levels, T)
data$country <- factor(data$country, levels = column.levels)

但在這里,國家是硬編碼的,排序不是參考。 我期望在一個函數中使用此代碼,該函數應該使用不同的數據集,以及其他列名。 那么如何讓它與存儲在變量中的列名一起使用,並且可能通過引用呢?

作為參考,數據旨在使用Plotly以條形圖形式呈現。 在哪里我想操縱訂單。 如這里所討論的( 2 ),這樣做的方法是重新排序因子水平。

非常感謝幫助!


澄清re: factor()setattr()

感謝@Uwe的反饋。 讓我試着讓自己更清楚。 我認為是什么問題。 我設法動態選擇列,這只是使用data[["column"]]而不是data$country的簡單問題,但我第一次嘗試時一定做錯了。 這留下了通過引用重新排序級別的問題。

這是數據的輸入:

dput(data)
structure(list(indicator = structure(c(1L, 1L, 1L, 1L, 1L, 1L
), .Label = "EN.ATM.CO2E.PC", class = "factor"), country = structure(1:6, .Label = c("Canada", 
"China", "European Union", "India", "Saudi Arabia", "United States"
), class = "factor"), year = structure(c(1L, 1L, 1L, 1L, 1L, 
1L), class = "factor", .Label = "2011"), value = c(15.6397596234201, 
7.24151541889549, 7.07937396032502, 1.47668634979755, 17.7023072439215, 
16.9724170879273)), .Names = c("indicator", "country", "year", 
"value"), sorted = c("indicator", "country", "year"), class = c("data.table", 
"data.frame"), row.names = c(NA, -6L), .internal.selfref = <pointer: 0x00000000001f0788>)

這是當我使用factor重新排序country列時會發生什么:

column.levels <- levels(data[["country"]])
column.levels <- sort(column.levels, T)
data[["country"]] <- factor(data[["country"]], levels = column.levels)

levels(data[["country"]]) #just as desired
[1] "United States"  "Saudi Arabia"   "India"          "European Union" "China"          "Canada" 

print(data) #nominal order unchanged
        indicator        country year     value
1: EN.ATM.CO2E.PC         Canada 2011 15.639760
2: EN.ATM.CO2E.PC          China 2011  7.241515
3: EN.ATM.CO2E.PC European Union 2011  7.079374
4: EN.ATM.CO2E.PC          India 2011  1.476686
5: EN.ATM.CO2E.PC   Saudi Arabia 2011 17.702307
6: EN.ATM.CO2E.PC  United States 2011 16.972417

該表未被刪除,但會根據需要重新排序。

但是這是使用setattr()發生的事情:

setattr(data[["country"]], "levels", column.levels)
#Also tried this, same result: data[,setattr(country, "levels", column.levels)]

levels(data[["country"]]) #well this looks good...
[1] "United States"  "Saudi Arabia"   "India"          "European Union" "China"          "Canada" 

print(data) #but this is absurd...
        indicator        country year     value
1: EN.ATM.CO2E.PC  United States 2011 15.639760
2: EN.ATM.CO2E.PC   Saudi Arabia 2011  7.241515
3: EN.ATM.CO2E.PC          India 2011  7.079374
4: EN.ATM.CO2E.PC European Union 2011  1.476686
5: EN.ATM.CO2E.PC          China 2011 17.702307
6: EN.ATM.CO2E.PC         Canada 2011 16.972417

因此,factor()使數據的名義順序保持不變。 但是setattr()實際上改變了國家列的名義順序,造成了嚴重破壞。 那么這里出了什么問題? 我對行為上的差異感到困惑。 是否可以使用setattr()或其他方法通過引用重新排序列因子級別? 希望我現在明白了!

通過引用修改data.table對象的列,即不復制整個對象,可以使用:=運算符,如下所示:

col <- "country"
DT[, (col) := factor(get(col), levels = rev(levels(get(col))))]
str(DT)
 Classes 'data.table' and 'data.frame': 6 obs. of 4 variables: $ indicator: Factor w/ 1 level "EN.ATM.CO2E.PC": 1 1 1 1 1 1 $ country : Factor w/ 6 levels "United States",..: 6 5 4 3 2 1 $ year : Factor w/ 1 level "2011": 1 1 1 1 1 1 $ value : num 15.64 7.24 7.08 1.48 17.7 ... 
DT
  indicator country year value 1: EN.ATM.CO2E.PC Canada 2011 15.639760 2: EN.ATM.CO2E.PC China 2011 7.241515 3: EN.ATM.CO2E.PC European Union 2011 7.079374 4: EN.ATM.CO2E.PC India 2011 1.476686 5: EN.ATM.CO2E.PC Saudi Arabia 2011 17.702307 6: EN.ATM.CO2E.PC United States 2011 16.972417 

請注意, DT用作data.table對象的名稱,以避免名稱與data()函數沖突。

由於factor()默認按字母順序對級別進行排序,因此rev()用於反轉現有因子級別的順序。

列名以變量col給出。 因此, get()用於訪問列。 或者,這可以寫成

DT[, (col) := lapply(.SD, factor, levels = rev(levels(DT[[col]]))), .SDcols = col]

使用特殊符號.SD.SDcols參數。

要驗證DT是否通過引用更新,可以使用address(DT)


為什么setattr()不能按預期工作?

setattr()似乎只是改變級別的標簽,而不是OP想要的級別編號。

DT
  indicator country year value 1: EN.ATM.CO2E.PC Canada 2011 15.639760 2: EN.ATM.CO2E.PC China 2011 7.241515 3: EN.ATM.CO2E.PC European Union 2011 7.079374 4: EN.ATM.CO2E.PC India 2011 1.476686 5: EN.ATM.CO2E.PC Saudi Arabia 2011 17.702307 6: EN.ATM.CO2E.PC United States 2011 16.972417 
DT[, as.integer(country)]
 [1] 1 2 3 4 5 6 
setattr(DT[[col]], "levels", rev(levels(DT[[col]])))
DT
  indicator country year value 1: EN.ATM.CO2E.PC United States 2011 15.639760 2: EN.ATM.CO2E.PC Saudi Arabia 2011 7.241515 3: EN.ATM.CO2E.PC India 2011 7.079374 4: EN.ATM.CO2E.PC European Union 2011 1.476686 5: EN.ATM.CO2E.PC China 2011 17.702307 6: EN.ATM.CO2E.PC Canada 2011 16.972417 
DT[, as.integer(country)]
 [1] 1 2 3 4 5 6 

如果使用上面的代碼,則相應地更改級別的編號:

DT[, (col) := factor(get(col), levels = rev(levels(get(col))))]
DT[, as.integer(country)]
 [1] 6 5 4 3 2 1 

(由於DT已經修改到位,請始終使用DT的新副本)

暫無
暫無

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

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