Сортировка столбца данных по каждому столбцу

Предположим, у меня есть фрейм данных с 3 столбцами (name, y, sex), где 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?

Ответ 1

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

Ответ 2

Вот краткое изложение всех методов, упомянутых в других ответах/комментариях (для обслуживания будущих поисковиков). Я добавил метод сортировки 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),]

Вот еще один вопрос, который касается того же

Ответ 3

Я думаю, что должна быть какая-то функция, например, для применения в кадрах данных и получить данные в качестве возврата

Да, есть:

library(plyr)

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

Ответ 4

Мне кажется, что вы пытаетесь сделать заказ по партитуре среди самцов и женщин и вернуть объединенный фрейм данных отсортированных самцов и отсортированных женщин.

Вы правы, что by(score, score$sex, function(x) x[order(x$y),]) возвращает список отсортированных кадров данных, один для мужчин и один для женщин. Вы можете использовать do.call с помощью функции rbind для объединения этих кадров данных в один конечный кадр данных:

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