web-dev-qa-db-ja.com

データフレーム列を係数で並べ替え

3つの列(nameysex)のデータフレームがあるとします。ここで、nameは文字、yは数値です値とsexは要因です。

sex<-c("M","M","F","M","F","M","M","M","F")
x<-c("MARK","TOM","SUSAN","LARRY","EMMA","LEONARD","TIM","MATT","Violet")
name<-as.character(x)
y<-rnorm(9,8,1)
score<-data.frame(x,y,sex)
score
     name      y     sex
1    MARK  6.767086   M
2     TOM  7.613928   M
3   SUSAN  7.447405   F
4   LARRY  8.040069   M
5    EMMA  8.306875   F
6 LEONARD  8.697268   M
7     TIM 10.385221   M
8    MATT  7.497702   M
9  Violet 10.177969   F

yで注文する場合は、次を使用します。

score[order(score$y),]
        x         y sex
1    MARK  6.767086   M
3   SUSAN  7.447405   F
8    MATT  7.497702   M
2     TOM  7.613928   M
4   LARRY  8.040069   M
5    EMMA  8.306875   F
6 LEONARD  8.697268   M
9  Violet 10.177969   F
7     TIM 10.385221   M

これまでのところ、非常に良い...名前は正しいスコアを維持していますが、MとFのレベルが混在しないように並べ替えるにはどうすればよいでしょうか。私は注文すると同時に、因子レベルを分けておく必要があります。

最後に、キャラクターを関与させるためにさらに一歩進んで、この例は役に立たないが、yの値が結びついていて、因子内で再度注文しなければならない場合(たとえば、TIMとTOMは8.4とアルファベット順を割り当てる必要があります)。

私は機能別に考えていましたが、それはリストを作成し、本当に助けにはなりません。データフレームに適用して戻り値としてデータフレームを取得するには、そのような関数が必要だと思います。

ポイントをクリアするには:

sep<-split(score,score$sex)
sep$M<-sep$M[order(sep$M[,2]),]
sep$M
x         y sex
1    MARK  6.767086   M
8    MATT  7.497702   M
2     TOM  7.613928   M
4   LARRY  8.040069   M
6 LEONARD  8.697268   M
7     TIM 10.385221   M

sep$F<-sep$F[order(sep$F[,2]),]
sep$F
x         y sex
3  SUSAN  7.447405   F
5   EMMA  8.306875   F
9 Violet 10.177969   F

merged<-rbind(sep$M,sep$F)
merged
x         y sex
1    MARK  6.767086   M
8    MATT  7.497702   M
2     TOM  7.613928   M
4   LARRY  8.040069   M
6 LEONARD  8.697268   M
7     TIM 10.385221   M
3   SUSAN  7.447405   F
5    EMMA  8.306875   F
9  Violet 10.177969   F

2つまたは3つの要素がある場合、その方法を知っています。しかし、20という深刻なレベルの要因がある場合、forループを作成する必要がありますか?

16
Matias Andina

orderは複数の引数を取り、必要なことだけを行います。

with(score, score[order(sex, y, x),])
##         x        y sex
## 3   SUSAN 6.636370   F
## 5    EMMA 6.873445   F
## 9  Violet 8.539329   F
## 6 LEONARD 6.082038   M
## 2     TOM 7.812380   M
## 8    MATT 8.248374   M
## 4   LARRY 8.424665   M
## 7     TIM 8.754023   M
## 1    MARK 8.956372   M
23

以下は、他の回答/コメントで言及されているすべての方法の要約です(将来の検索者に役立つため)。ソートのdata.table方法を追加しました。

# Base R
do.call(rbind, by(score, score$sex, function(x) x[order(x$y),]))
with(score, score[order(sex, y, x),])
score[order(score$sex,score$x),]

# Using plyr
arrange(score, sex,y)
ddply(score, c('sex', 'y'))

# Using `data.table`
library("data.table")
score_dt <- setDT(score)

# setting a key works just fine
setkey(score_dt,sex,x)
print(score_dt)

# Explicitly ordering using i
score_dt[i=order(sex,x),]

これを扱う別の質問があります

9
marbel

データフレームに適用し、戻り値としてデータフレームを取得するには、そのような関数が必要だと思います

はいあります:

library(plyr)

ddply(score, c('y', 'sex'))
3
John

あなたは男性と女性の中でスコア順に並べ、ソートされた男性とソートされた女性の結合されたデータフレームを返そうとしているように思えます。

by(score, score$sex, function(x) x[order(x$y),])は、男性用と女性用のソートされたデータフレームのリストを返すのは正しいです。 do.callrbind関数とともに使用して、これらのデータフレームを1つの最終データフレームに結合できます。

do.call(rbind, by(score, score$sex, function(x) x[order(x$y),]))
#           x         y sex
# F.5    EMMA  7.526866   F
# F.9  Violet  8.182407   F
# F.3   SUSAN  9.677511   F
# M.4   LARRY  6.929395   M
# M.8    MATT  7.970015   M
# M.7     TIM  8.297137   M
# M.6 LEONARD  8.845588   M
# M.2     TOM  9.035948   M
# M.1    MARK 10.082314   M
2
josliber