2017-08-06 6 views
0

するのではなく、リストを返します -sapplyは()私は、次のデータフレームを持つベクトル

名前が一人、amarks、bmarksとcmarksの名前であるマークは、人によって異なる試験で採点され
name amarks bmarks cmarks 
1 A 25  30  40 
2 B 45  78  50 
3 C 75  72  29 
4 D 18  16  70 
. . .  .  . 

。今、私はamarks、bmarks、およびcmarksでmaxを獲得した人々の名前を見つけることを任されています。また、私はベクトルとしてそれを格納する必要があります。私は、次の方法でそれを解決した -

> 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はリストを返しました。列ごとに1つの結果が常に必要な場合は、代わりに '?which.max'を参照してください。また、あなたの望む結果は何ですか? 'サプリ(マーク[、2:4]、マックス、na.rm = TRUE)'だけで十分でしょうか? –

+1

あるいは、 '$ name [sapply(marks [、2:4]、which.max)]'をマークします。また、 'subset'はデータフレームを返します。理論的には、コードの最後に '、drop = TRUE'を追加することができます。そして、1つのカラムにつき常に1つの' max'があれば、結果として文字ベクトルが得られます。 –

+0

Davidさん、ありがとうございました。 – user1305398

答えて

3

あなたはあなたのコードでいくつかの問題を抱えて:データフレームのための

  1. subset方法は、(明示的, drop = TRUEを指定しますしない限り)あなたは常には見返りにデータフレームを取得することを意味しますデフォルトとして, drop = FALSEセットを持っています。したがって、listベクタが結果として得られます。これは、複数のデータフレームをまとめて保持できるR内の唯一の構造体であるためです(また、?subsetドキュメントの「警告」セクションと、については )。
  2. x == max(...各列に最大値に等しい値が複数ある可能性があるため、不明な行数を返すことができます。したがって、確かに結果として異なる長さベクトルが得られますが、listだけが異なるサイズベクトルを保持できます。列ごとに1つの結果だけが必要な場合は、たとえばwhich.maxを使用すると、NAが自動的に無視されます。
  3. 最後に、リストではなく実際に何が期待されていたのかはあまり明確ではありませんか?最大値に等しい列に複数の行がある場合は、両方の名前が必要ですか?または最初の?どちらの方は、下記

が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 

を異なる方法を見ることができたのは、いくつかのNA sおよび列に等しいいくつかの重複行を追加してみましょう、いくつかのオプションがあります。すべてnameの私たちは自分のコードに

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" 

代替方法のない同じことを達成することをunlistを追加することができます外部パッケージを使用するための交換、マトリックス変換及び一般超上で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も扱います)

marks$name[sapply(marks[, 2:4], which.max)] 
# [1] "C" "B" "C" 
関連する問題