2017-08-06 71 views
0

我有以下的數據幀 -sapply()返回,而不是一個向量列表

name amarks bmarks cmarks 
1 A 25  30  40 
2 B 45  78  50 
3 C 75  72  29 
4 D 18  16  70 
. . .  .  . 

name是人的名字,amarks,bmarks和cmarks是標記在不同的檢查得分由人。現在我的任務是找出在amarks,bmarks和cmarks中得分最高的人的姓名。另外我還將它作爲矢量存儲。我已經通過以下方式解決了這個問題 -

> max_name <- sapply(marks[,2:4], function(x) {subset(marks, x == max(x, 
> na.rm = T), name)}) 

這給了我正確的答案,但是當我檢查max_name的數據類型,我看到它的列表時,最好我預計sapply返回向量。

以下是我的意見 -

class(max_name) 

> list 

typeof(max_name) 

> list 

is.vector(max_name) 

> vector 

有人可以請解釋正在發生的事情在這裏。我錯過了什麼。我是否需要對我的代碼進行任何更改,以便它返回一個向量?

+4

首先'list' *是一個向量。其次,當你做'x == max'之類的事情時,你永遠不知道會得到多少結果。它可以是1或1千。在R中,只有一個列表可以存儲不同大小的向量,因此R返回一個列表。如果您總是希望每列有一個結果,請參閱'?which.max'。另外,你期望的結果是什麼?不僅僅是'sapply(標記[,2:4],max,na.rm = TRUE)'就足夠了? –

+1

或者'也許'標記$ name [sapply(marks [,2:4],which.max)]''。另外,'subset'返回一個數據幀。理論上,您可以在代碼的末尾添加',drop = TRUE',並且如果每列總是有一個'max',那麼您將得到一個字符向量。 –

+0

感謝大衛,幫助。 – user1305398

回答

3

你必須與你的代碼的幾個問題:

  1. subset爲dataframes方法, drop = FALSE設置爲默認值,這意味着你將總是會得到回報一個數據幀(除非你明確指定, drop = TRUE) 。因此,您總是會得到一個list向量,因爲這是R中唯一可以同時保存多個數據幀的結構(同時請注意?subset文檔中的「Warning」部分,說明何時使用,如果應該使用它)。
  2. x == max(...可以返回未知數量的行,因爲在每列中可能有幾個值等於最大值。因此,大多數情況下,您會得到不同的長度向量,並且,只有list可以保存不同大小的向量。如果您只希望每列有單個結果,則可以使用which.max,這也會自動忽略NA s。
  3. 最後,你不是很清楚你實際期望的是什麼,而不是一個列表?如果列中有多個行等於最大值,那麼您是否想要這兩個名稱?還是隻有第一個?非此即彼的方式,下面是幾個選項

讓我們添加一些NA S和它等於列的一些重複的行MAXS,所以我們可以看到結果基本不同

marks <- read.table(text = "name amarks bmarks cmarks 
1 A NA  30  40 
2 B 45  78  50 
3 C 75  NA  70 
4 D 75  16  70", header = TRUE, stringsAsFactors = FALSE) 

marks 
# name amarks bmarks cmarks 
# 1 A  NA  30  40 
# 2 B  45  78  50 
# 3 C  75  NA  70 
# 4 D  75  16  70 

,如果你想所有name小號,我們可以只添加unlist到您的代碼

unlist(sapply(marks[, 2:4], function(x) {subset(marks, x == max(x, na.rm = TRUE), name)})) 
# amarks.name1 amarks.name2 bmarks.name cmarks.name1 cmarks.name2 
#   "C"   "D"   "B"   "C"   "D" 

替代方式達到相同的無使用subset

marks$name[unlist(sapply(marks[, 2:4], function(x) which(x == max(x, na.rm = TRUE))))] 
## [1] "C" "D" "B" "C" "D" 

或者甚至(向量化/過併發症權衡)

marks$name[which(sapply(marks[, 2:4], 
         function(x) x == max(x, na.rm = TRUE)), arr.ind = TRUE)[, "row"]] 
## [1] "C" "D" "B" "C" "D" 

或完全矢量化溶液(在交換使用外部封裝,矩陣變換和通常超過-complication)

marks$name[which(marks[, 2:4] == matrixStats::colMaxs(as.matrix(marks[, 2:4]), 
                 na.rm = TRUE)[col(marks[, 2:4])], 
       arr.ind = TRUE)[, "row"]] 

## [1] "C" "D" "B" "C" "D" 

不過,如果你只是想第一馬克西媽媽每列,我們可以簡化爲(其中還處理NA s)

marks$name[sapply(marks[, 2:4], which.max)] 
# [1] "C" "B" "C" 
相關問題