我有一个看起来像这个例子的数据帧(只是大得多):
var <- c('Peter','Ben','Mary','Peter.1','Ben.1','Mary.1','Peter.2','Ben.2','Mary.2')
v1 <- c(0.4, 0.6, 0.7, 0.3, 0.9, 0.2, 0.4, 0.6, 0.7)
v2 <- c(0.5, 0.4, 0.2, 0.5, 0.4, 0.2, 0.1, 0.4, 0.2)
df <- data.frame(var, v1, v2)
var v1 v2
1 Peter 0.4 0.5
2 Ben 0.6 0.4
3 Mary 0.7 0.2
4 Peter.1 0.3 0.5
5 Ben.1 0.9 0.4
6 Mary.1 0.2 0.2
7 Peter.2 0.4 0.1
8 Ben.2 0.6 0.4
9 Mary.2 0.7 0.2
我想根据没有后缀的名称对"var"中的字符串进行分组,并保持首次出现的原始顺序。期望输出:
var v1 v2
1 Peter 0.4 0.5 # Peter appears first in the original data
2 Peter.1 0.3 0.5
3 Peter.2 0.4 0.1
4 Ben 0.6 0.4 # Ben appears second in the original data
5 Ben.1 0.9 0.4
6 Ben.2 0.6 0.4
7 Mary 0.7 0.2 # Mary appears third in the original data
8 Mary.1 0.2 0.2
9 Mary.2 0.7 0.2
我怎样才能做到这一点?
谢谢!
一个选项是创建一个临时列,不带.
和数字(\d+
)在末尾加上str_remove
,然后使用factor
指定为unique
值levels
或使用match
来arrange
数据
library(dplyr)
library(stringr)
df <- df %>%
mutate(var1 = str_remove(var, "\.\d+$")) %>%
arrange(factor(var1, levels = unique(var1))) %>%
select(-var1)
或者使用forcats
中的fct_inorder
,它将按首次出现的顺序转换为带有levels
的factor
library(forcats)
df %>%
arrange(fct_inorder(str_remove(var, "\.\d+$")))
-输出
var v1 v2
1 Peter 0.4 0.5
2 Peter.1 0.3 0.5
3 Peter.2 0.4 0.1
4 Ben 0.6 0.4
5 Ben.1 0.9 0.4
6 Ben.2 0.6 0.4
7 Mary 0.7 0.2
8 Mary.1 0.2 0.2
9 Mary.2 0.7 0.2
带有sub
和data.table::chgroup
的紧凑选项
df[chgroup(sub("\..", "", df$var)),]
var v1 v2
1 Peter 0.4 0.5
4 Peter.1 0.3 0.5
7 Peter.2 0.4 0.1
2 Ben 0.6 0.4
5 Ben.1 0.9 0.4
8 Ben.2 0.6 0.4
3 Mary 0.7 0.2
6 Mary.1 0.2 0.2
9 Mary.2 0.7 0.2
chgroup
将重复的值组合在一起,但保留组顺序(根据每个组的第一次出现顺序),有效地
如果您不介意var
中的值按字母顺序排序,那么最简单的解决方案是这样的:
df %>%
arrange(var)
var v1 v2
1 Ben 0.6 0.4
2 Ben.1 0.9 0.4
3 Ben.2 0.6 0.4
4 Mary 0.7 0.2
5 Mary.1 0.2 0.2
6 Mary.2 0.7 0.2
7 Peter 0.4 0.5
8 Peter.1 0.3 0.5
9 Peter.2 0.4 0.1
separate
var
列分成两列,将生成的 NA 替换为 0,排序并删除多余的列。
这适用于数字的数值而不是字符表示形式,例如,10 不会在 2 之前出现。 此外,arrange
中的match
可确保订单基于第一个出现顺序。
df %>%
separate(var, c("alpha", "no"), convert=TRUE, remove=FALSE, fill="right") %>%
mutate(no = replace_na(no, 0)) %>%
arrange(match(alpha, alpha), no) %>%
select(-alpha, -no)
给
var v1 v2
1 Peter 0.4 0.5
2 Peter.1 0.3 0.5
3 Peter.2 0.4 0.1
4 Ben 0.6 0.4
5 Ben.1 0.9 0.4
6 Ben.2 0.6 0.4
7 Mary 0.7 0.2
8 Mary.1 0.2 0.2
9 Mary.2 0.7 0.2
更新
在阅读问题的更新后,删除了以前的第一个解决方案。