R 对数据框中组内的行进行编号

R 对数据框中组内的行进行编号,r,dataframe,r-faq,R,Dataframe,R Faq,使用与此类似的数据帧: set.seed(100) df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15)) df <- df[order(df$cat, df$val), ] df cat val 1 aaa 0.05638315 2 aaa 0.25767250 3 aaa 0.3077

使用与此类似的数据帧:

set.seed(100)  
df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15))             
df <- df[order(df$cat, df$val), ]  
df  

   cat        val  
1  aaa 0.05638315  
2  aaa 0.25767250  
3  aaa 0.30776611  
4  aaa 0.46854928  
5  aaa 0.55232243  
6  bbb 0.17026205  
7  bbb 0.37032054  
8  bbb 0.48377074  
9  bbb 0.54655860  
10 bbb 0.81240262  
11 ccc 0.28035384  
12 ccc 0.39848790  
13 ccc 0.62499648  
14 ccc 0.76255108  
15 ccc 0.88216552 
set.seed(100)

df使用
ave
ddply
dplyr
数据。表

df$num <- ave(df$val, df$cat, FUN = seq_along)
df$num <- sequence(rle(df$cat)$lengths)
> set.seed(100)  
> df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15))
> df <- df[order(df$cat, df$val), ]  
> df$num <- data.table::rowid(df$cat)
> df
   cat        val num
4  aaa 0.05638315   1
2  aaa 0.25767250   2
1  aaa 0.30776611   3
5  aaa 0.46854928   4
3  aaa 0.55232243   5
10 bbb 0.17026205   1
8  bbb 0.37032054   2
6  bbb 0.48377074   3
9  bbb 0.54655860   4
7  bbb 0.81240262   5
13 ccc 0.28035384   1
14 ccc 0.39848790   2
11 ccc 0.62499648   3
15 ccc 0.76255108   4
12 ccc 0.88216552   5
或:

或者(内存效率最高,在
DT
中通过引用分配):

库(data.table)

DT这里有一个选项,使用
按组循环,而不是按行循环(像OP那样)

for(i in unique(df$cat))df$num[df$cat==i]为了使这个问题更完整,一个带有
序列和
rle的基本R替代方案:

df$num <- ave(df$val, df$cat, FUN = seq_along)
df$num <- sequence(rle(df$cat)$lengths)
> set.seed(100)  
> df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15))
> df <- df[order(df$cat, df$val), ]  
> df$num <- data.table::rowid(df$cat)
> df
   cat        val num
4  aaa 0.05638315   1
2  aaa 0.25767250   2
1  aaa 0.30776611   3
5  aaa 0.46854928   4
3  aaa 0.55232243   5
10 bbb 0.17026205   1
8  bbb 0.37032054   2
6  bbb 0.48377074   3
9  bbb 0.54655860   4
7  bbb 0.81240262   5
13 ccc 0.28035384   1
14 ccc 0.39848790   2
11 ccc 0.62499648   3
15 ccc 0.76255108   4
12 ccc 0.88216552   5
如果
df$cat
是一个因子变量,则需要将其包装为.character
首先:

df$num <- sequence(rle(as.character(df$cat))$lengths)

df$num我想使用
rank()
函数添加一个
data.table
变量,它提供了更改顺序的额外可能性,因此比
seq_len()
解决方案更灵活,与RDBMS中的行数函数非常类似

# Variant with ascending ordering
library(data.table)
dt <- data.table(df)
dt[, .( val
   , num = rank(val))
    , by = list(cat)][order(cat, num),]

    cat        val num
 1: aaa 0.05638315   1
 2: aaa 0.25767250   2
 3: aaa 0.30776611   3
 4: aaa 0.46854928   4
 5: aaa 0.55232243   5
 6: bbb 0.17026205   1
 7: bbb 0.37032054   2
 8: bbb 0.48377074   3
 9: bbb 0.54655860   4
10: bbb 0.81240262   5
11: ccc 0.28035384   1
12: ccc 0.39848790   2
13: ccc 0.62499648   3
14: ccc 0.76255108   4

# Variant with descending ordering
dt[, .( val
   , num = rank(desc(val)))
    , by = list(cat)][order(cat, num),]
#具有升序的变体
库(数据表)

dt这里有一个小的改进技巧,允许在组内排序“val”:

# 1. Data set
set.seed(100)
df <- data.frame(
  cat = c(rep("aaa", 5), rep("ccc", 5), rep("bbb", 5)), 
  val = runif(15))             

# 2. 'dplyr' approach
df %>% 
  arrange(cat, val) %>% 
  group_by(cat) %>% 
  mutate(id = row_number())
#1。数据集
种子集(100)
df%
排列(类别,val)%>%
分组依据(类别)%>%
变异(id=行号()

另一种可能性是:

df %>%
 group_by(cat) %>%
 mutate(num = 1:n())

   cat      val   num
   <fct>  <dbl> <int>
 1 aaa   0.0564     1
 2 aaa   0.258      2
 3 aaa   0.308      3
 4 aaa   0.469      4
 5 aaa   0.552      5
 6 bbb   0.170      1
 7 bbb   0.370      2
 8 bbb   0.484      3
 9 bbb   0.547      4
10 bbb   0.812      5
11 ccc   0.280      1
12 ccc   0.398      2
13 ccc   0.625      3
14 ccc   0.763      4
15 ccc   0.882      5
df%>%
分组依据(类别)%>%
变异(num=1:n())
猫瓦尔数
1 aaa 0.0564 1
2 aaa 0.258 2
3 aaa 0.308 3
4 aaa 0.469 4
5 aaa 0.552 5
6 bbb 0.170 1
7 bbb 0.370 2
8 bbb 0.484 3
9 bbb 0.547 4
10 bbb 0.812 5
11 ccc 0.280 1
12 ccc 0.398 2
13 ccc 0.625 3
14 ccc 0.763 4
15 ccc 0.882 5
使用
数据中的
rowid()
函数。表

df$num <- ave(df$val, df$cat, FUN = seq_along)
df$num <- sequence(rle(df$cat)$lengths)
> set.seed(100)  
> df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15))
> df <- df[order(df$cat, df$val), ]  
> df$num <- data.table::rowid(df$cat)
> df
   cat        val num
4  aaa 0.05638315   1
2  aaa 0.25767250   2
1  aaa 0.30776611   3
5  aaa 0.46854928   4
3  aaa 0.55232243   5
10 bbb 0.17026205   1
8  bbb 0.37032054   2
6  bbb 0.48377074   3
9  bbb 0.54655860   4
7  bbb 0.81240262   5
13 ccc 0.28035384   1
14 ccc 0.39848790   2
11 ccc 0.62499648   3
15 ccc 0.76255108   4
12 ccc 0.88216552   5
>设置种子(100)
>df$num df
猫瓦尔数
4 aaa 0.05638315 1
2 aaa 0.25767250 2
1 aaa 0.30776611 3
5 aaa 0.46854928 4
3 aaa 0.55232243 5
10桶0.17026205 1
8 bbb 0.37032054 2
6 bbb 0.48377074 3
9 bbb 0.54655860 4
7 bbb 0.81240262 5
13 ccc 0.28035384 1
14 ccc 0.39848790 2
11 ccc 0.62499648 3
15 ccc 0.76255108 4
12 ccc 0.88216552 5

另一个基本R解决方案是按照
cat
拆分数据帧,然后使用
lapply
:添加一个编号为
1:nrow(x)
的列。最后一步是使用
do.call
返回最终数据帧,即:

        df_split <- split(df, df$cat)
        df_lapply <- lapply(df_split, function(x) {
          x$num <- seq_len(nrow(x))
          return(x)
        })
        df <- do.call(rbind, df_lapply)

df_split非常简单、整洁的解决方案

整个数据帧的行号

库(tidyverse)
虹膜%>%
变异(行数=沿萼片长度排列))%>%
头
萼片。长萼片。宽花瓣。长花瓣。宽种行数
1 5.1 3.5 1.4 0.2 1
2 4.9 3.0 1.4 0.2 setosa 2
3 4.7 3.2 1.3 0.2 3
..           ...         ...          ...         ...     ......     ...
148 6.5 3.0 5.2 2.0弗吉尼亚州148
149 6.2 3.4 5.4 2.3弗吉尼亚州149
150 5.9 3.0 5.1 1.8弗吉尼亚州150
数据框中分组的行号

iris%>%
组别(种类)%>%
变异(群体中的数量=沿着(物种)的顺序))%>%
as.data.frame
萼片。长萼片。宽花瓣。长花瓣。宽种数
1 5.1 3.5 1.4 0.2 1
2 4.9 3.0 1.4 0.2 setosa 2
3 4.7 3.2 1.3 0.2 3
..           ...         ...          ...         ...     ......           ..
48 4.6 3.2 1.4 0.2刚毛48
49 5.3 3.7 1.5 0.2刚毛49
50 5.0 3.3 1.4 0.2刚毛50
51 7.0 3.2 4.7 1.4彩色1
52 6.4 3.2 4.5 1.5彩色2
53 6.9 3.1 4.9 1.5彩色3
..           ...         ...          ...         ...     ......           ..
98 6.2.9 4.3 1.3花色48
99 5.1 2.5 3.0 1.1花色49
100 5.7 2.8 4.1 1.3彩色50
101 6.3.3 6.0 2.5弗吉尼亚州1
102 5.8 2.7 5.1 1.9弗吉尼亚州2
103 7.1 3.0 5.9 2.1弗吉尼亚州3
..           ...         ...          ...         ...     ......           ..
148 6.5 3.0 5.2 2.0弗吉尼亚州48
149 6.2 3.4 5.4 2.3弗吉尼亚州49
150 5.9 3.0 5.1 1.8弗吉尼亚州50

值得一提的是,
ave
在这里给出的是浮点而不是int。或者,可以将
df$val
更改为
seq_len(nrow(df))
。我刚刚在这里遇到了这个问题:有趣的是,这个
数据表
解决方案似乎比使用
frank
库(microbenchmark)更快;微基准(a=DT[,(val,num=frank(val)),by=list(cat)],b=DT[,(val,id=seq_len(.N)),by=list(cat)],times=1000L)
谢谢!
dplyr
解决方案很好。但是,如果像我一样,在尝试这种方法时不断出现奇怪的错误,请确保在
plyr
dplyr