Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
261 views
in Technique[技术] by (71.8m points)

r - Order a "mixed" vector (numbers with letters)

How can I order a vector like

c("7","10a","10b","10c","8","9","11c","11b","11a","12") -> alph

in

alph
[1] "7","8","9","10a","10b","10c","11a","11b","11c","12"

and use it to sort a data.frame, like

V1 <- c("A","A","B","B","C","C","D","D","E","E")
V2 <- 2:1 
V3 <- alph
df <- data.frame(V1,V2,V3)

and order the row to obtain (order V2 and then V3)

 V1 V2  V3
C  1   9
A  1 10a
B  1 10c
D  1 11b
E  1  12
A  2   7
C  2   8
B  2 10b
E  2 11a
D  2 11c
Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
> library(gtools)
> mixedsort(alph)

[1] "7"   "8"   "9"   "10a" "10b" "10c" "11a" "11b" "11c" "12" 

To sort a data.frame you use mixedorder instead

> mydf <- data.frame(alph, USArrests[seq_along(alph),])
> mydf[mixedorder(mydf$alph),]

            alph Murder Assault UrbanPop Rape
Alabama        7   13.2     236       58 21.2
California     8    9.0     276       91 40.6
Colorado       9    7.9     204       78 38.7
Alaska       10a   10.0     263       48 44.5
Arizona      10b    8.1     294       80 31.0
Arkansas     10c    8.8     190       50 19.5
Florida      11a   15.4     335       80 31.9
Delaware     11b    5.9     238       72 15.8
Connecticut  11c    3.3     110       77 11.1
Georgia       12   17.4     211       60 25.8

mixedorder on multiple vectors (columns)

Apparently mixedorder cannot handle multiple vectors. I have made a function that circumvents this by converting all character vectors to factors with mixedsorted sorted levels, and pass all vectors on to the standard order function.

multi.mixedorder <- function(..., na.last = TRUE, decreasing = FALSE){
    do.call(order, c(
        lapply(list(...), function(l){
            if(is.character(l)){
                factor(l, levels=mixedsort(unique(l)))
            } else {
                l
            }
        }),
        list(na.last = na.last, decreasing = decreasing)
    ))
}

However, in your particular case multi.mixedorder gets you the same result as the standard order, since V2 is numeric.

df <- data.frame(
    V1 = c("A","A","B","B","C","C","D","D","E","E"),
    V2 = 19:10,
    V3 = alph,
    stringsAsFactors = FALSE)

df[multi.mixedorder(df$V2, df$V3),]

   V1 V2  V3
10  E 10  12
9   E 11 11a
8   D 12 11b
7   D 13 11c
6   C 14   9
5   C 15   8
4   B 16 10c
3   B 17 10b
2   A 18 10a
1   A 19   7

Notice that

  • 19:10 is equivalent to c(19:10). c means concat, that is to make one long vector out of many short, but in you case you only have one vector (19:10) so there's no need to concat anything. However, in the case of V1 you have 10 vectors of length 1, so there you need to concat, as you already do.
  • You need stringsAsFactors=FALSE to not convert V1 and V3 to (incorrectly sorted) factors (which is default).

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...