我正在尝试使用dplyr::arrange
订购数据框。问题是我尝试排序的列包含一个固定字符串后跟一个数字,例如由下面的虚拟代码生成。
dummydf<-data.frame(values=rnorm(100),sortcol=paste0("ABC",sample(1:100,100,replace=FALSE)))
默认情况下,使用dummydf %>% arrange(sortcol)
会生成一个按字母数字(?)排序的df,但这当然不是理想的结果:
values sortcol
0.708081720 ABC1
0.041348322 ABC10
1.730962886 ABC100
0.423480861 ABC11
-1.545837266 ABC12
-1.345539947 ABC13
-0.078998792 ABC14
0.088712174 ABC15
0.670583024 ABC16
1.238837680 ABC17
-1.459044293 ABC18
-2.028535223 ABC19
0.779514385 ABC2
1.360509910 ABC20
在这个例子中,我想按gtools::mixedsort
的方式对列进行排序,确保ABC2跟在ABC1之后,并且不在ABC1-19之前,而ABC100 mixedsort(as.character(dummydf$sortcol))
也会这样做。
现在,我知道我可以在我的sub
参数arrange
中使用dummydf %>% arrange(as.numeric(sub("ABC","",sortcol)))
来做到这一点,但这主要是因为我的字符串是固定的(尽管可以使用任何正则表达式)捕获任何字符串后面的最后数字我想。
我只是想知道:是否有更“优雅”和通用的方法来完成dplyr::arrange
,与gtools::mixedsort
一样?
亲切的问候,
FM
答案 0 :(得分:4)
这是一个利用mysterious身份order(order(x)) == rank(x)
的功能解决方案。
mixedrank = function(x) order(gtools::mixedorder(x))
dummydf %>% dplyr::arrange(mixedrank(sortcol))
答案 1 :(得分:2)
使用data.table
library(data.table)
dummydf = data.table(dummydf)
dummydf[gtools::mixedorder(as.character(sortcol))]
老实说,只是复制了你的例子并将其作为data.table
语法中的select参数插入。你已经完成了所有艰苦的工作:)。
答案 2 :(得分:1)
我没有看到这个答案发布,所以我会把它扔掉。您可以使用带有切片的混合顺序来排列它。
dummydf %>%
slice(mixedorder(sortcol))
答案 3 :(得分:0)
感谢Akhil Nair的data.table
答案,这是第一个代码段的来源。如果您喜欢data.table
的答案,但仍希望使用magrittr
管道,则可以考虑计算新列,并将管道与data.table
一起使用以获取输出:
dummydf %>%
dplyr::mutate(row_lookup = gtools::mixedorder(as.character(sortcol))) %>%
data.table::data.table() %>%
.[.$row_lookup]
我认为这是否有助于或损害可读性尚待商。
如果您不想调用data.table
,则可以进行一些额外的计算来计算可以使用dplyr::arrange
的列。这是一个示例:
library(dplyr)
bind_cols(dummydf,
dummydf %>%
tibble::rowid_to_column("order") %>%
mutate(rowname = gtools::mixedorder(as.character(sortcol))) %>%
arrange(rowname) %>%
select(order)) %>%
arrange(order)
我认为这段代码更容易阅读,不值得为了避免data.table
而过度扭曲。