在 R 中,基于一列创建唯一 ID,并根据生成的 ID 计算均值。

4

我正在尝试为每个事件/剧集生成唯一的ID,然后想根据生成的ID计算一列的平均值。

以下是一个示例:

事件 数值
A 3
A 5
A 1
B 8
B 2
C 1
C 3
A 2
A 5

首先,我想创建如下的ID列:

事件 价值 ID
A 3 A1
A 5 A1
A 1 A1
B 8 B1
B 2 B1
C 1 C1
C 3 C1
A 2 A2
A 5 A2

其次,我想基于生成的ID列计算'价值'的平均值。

感谢您的帮助和建议。

我尝试了'cumsum'和'duplicated'函数,但它们倾向于生成连续的ID号码。

4个回答

4
一个与 @ismirsehregal 相似的方法,但使用 dplyr。请注意,consecutive_id 是在 dplyr 1.1.0 中引入的,这是最新的 dplyr 更新。
library(dplyr) #1.1.0+ 
df %>% 
  mutate(id = consecutive_id(Event)) %>% 
  mutate(id = paste0(Event, consecutive_id(id)), .by = Event) %>%
  mutate(mean = mean(Val), .by = id)

  Event Val id mean
1     A   3 A1  3.0
2     A   5 A1  3.0
3     A   1 A1  3.0
4     B   8 B1  5.0
5     B   2 B1  5.0
6     C   1 C1  2.0
7     C   3 C1  2.0
8     A   2 A2  3.5
9     A   5 A2  3.5

另一种基于cumsum和非连续的row_number的方法:

df %>% 
  mutate(id = row_number()) %>% 
  mutate(id = paste0(Event, cumsum(c(0, diff(id)) != 1)), .by = Event) %>% 
  mutate(mean = mean(Val), .by = id)

4

一种 data.table 的方法:

library(data.table)

DT <- data.table(
    Event = c("A", "A", "A", "B", "B", "C", "C", "A", "A"),
    Val = c(3L, 5L, 1L, 8L, 2L, 1L, 3L, 2L, 5L)
  )

DT[, ID := rleid(Event)][, ID := rleid(ID), by = Event][, ID := paste0(Event, ID)][, mean := mean(Val), by = ID]

> DT
   Event Val ID mean
1:     A   3 A1  3.0
2:     A   5 A1  3.0
3:     A   1 A1  3.0
4:     B   8 B1  5.0
5:     B   2 B1  5.0
6:     C   1 C1  2.0
7:     C   3 C1  2.0
8:     A   2 A2  3.5
9:     A   5 A2  3.5

3
非常聪明地使用了 rleid +1 - Maël
1
我认为聪明的地方是使用它两次? - TarJae
1
是的,没错,而且还按组分类。 - Maël

3

更新第一个答案是不正确的!

这里是正确的版本(感谢@Maël),我使用了他的consecutive_id方法和rleid

library(dplyr)
library(data.table)

df %>%
  mutate(ID = rleid(Event)) %>% 
  mutate(ID = paste0(Event, rleid(ID)), .by = Event) %>% 
  mutate(mean = mean(Val), .by = ID)

  Event Val ID mean
1     A   3 A1  3.0
2     A   5 A1  3.0
3     A   1 A1  3.0
4     B   8 B1  5.0
5     B   2 B1  5.0
6     C   1 C1  2.0
7     C   3 C1  2.0
8     A   2 A2  3.5
9     A   5 A2  3.5

df %>%
  mutate(ID = rleid(Event)) %>% 
  mutate(ID = paste0(Event, rleid(ID)), .by = Event) %>% 
  mutate(mean = mean(Val), .by = ID)

第一条回答:不正确! 受到@ismirsehregal的解决方案的启发,这里呈现dplyr版本:

library(dplyr)

df %>% 
    group_by(Event) %>%
    mutate(ID = paste0(Event, cumsum(c(TRUE, diff(Val != lag(Val, default = first(Val))) != 0)))) %>%
    group_by(Event, ID) %>%
    mutate(mean = mean(Val)) %>%
    ungroup()

 Event   Val ID     mean
  <chr> <int> <chr> <dbl>
1 A         3 A1     3   
2 A         5 A2     3.25
3 A         1 A2     3.25
4 B         8 B1     8   
5 B         2 B2     2   
6 C         1 C1     1   
7 C         3 C2     3   
8 A         2 A2     3.25
9 A         5 A2     3.25

2
但是ID不正确,对吗?例如应该是C1 C1。 - Maël
没错,我会修复它。谢谢提醒。 - TarJae

1
这里有一个 dplyr 的解决方案,如果你想将平均值作为新列添加而不是将行数减少到每组一个,则使用 mutate
library(dplyr)
  
df %>% 
  group_by(ID = paste0(Event, cumsum(lag(Event, default = first(Event)) != Event) + 1)) %>% 
  summarize(Val = mean(Val), .groups = "drop")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接