【问题标题】:find sequences from rows of data从数据行中查找序列
【发布时间】:2020-11-23 00:21:31
【问题描述】:

我正在处理一个包含一系列“事件”及其发生日期的数据框。这些事件是连续的,一个接一个,但有多个独立的序列。

数据的结构使得每一行都显示一个事件 (event_name) 以及在序列中稍后某个时间点跟随它的事件 (later_event_name)。见下文:

   event_name  event_date later_event_name later_event_date
1           A  2020-01-01                B       2020-02-01
2           A  2020-01-01                C       2020-03-01
3           A  2020-01-01                G       2020-07-01
4           B  2020-02-01                C       2020-03-01
5           B  2020-02-01                G       2020-07-01
6           C  2020-03-01                G       2020-07-01
7           D  2020-04-01                F       2020-06-01
8           D  2020-04-01                I       2020-09-01
9           F  2020-06-01                I       2020-09-01
10          E  2020-05-01                H       2020-08-01

在这种情况下,FI都在D之后,IF之后,所以顺序是D->F->I

这个数据框中有三个序列:

  1. A->B->C->G
  2. D->F->I
  3. E->H

我的实际数据包含数千行。我希望能够自动化对组成每个序列的事件进行分组的过程。一个想法最终输出如下:

# the desired output
# `seq_id` is the identifier for each separate sequence
# `seq` shows the order of each event within that sequence
  seq_id seq event_name event_date
1      1   1          A 2020-01-01
2      1   2          B 2020-02-01
3      1   3          C 2020-03-01
4      1   4          G 2020-07-01
5      2   1          D 2020-04-01
6      2   2          F 2020-06-01
7      2   3          I 2020-09-01
8      3   1          E 2020-05-01
9      3   2          H 2020-08-01

这是虚拟数据:

# the input data
structure(list(event_name = c("A", "A", "A", "B", "B", "C", "D", "D", "F", "E"),
               event_date = structure(c(18262, 18262, 18262, 
                                        18293, 18293, 18322, 18353, 18353, 18414, 18383), class = "Date"),
               later_event_name = c("B", "C", "G", "C", "G", "G", "F", "I", "I", "H"),
               later_event_date = structure(c(18293, 18322, 18444, 
                                              18322, 18444, 18444, 18414, 18506, 18506, 18475), class = "Date")),
          row.names = c(NA, -10L), class = "data.frame")

一些注意事项:

  • 序列可以是从两个以上的任意长度。
  • 为简单起见,我在这里将事件命名为“A”、“B”等,但实际上它们的 ID 是没有逻辑模式或顺序的字母数字代码。

【问题讨论】:

  • 如果事件链分叉了怎么办?例如,A-->B 和 A-->C,但 B 和 C 发生在同一日期。
  • @ekoam 好问题!幸运的是,这些事件具有唯一的日期(它们不可能在同一天发生),因此不会出现此问题。

标签: r


【解决方案1】:

一种方法是将其概念化为网络图。如果数据按event_datelater_event_date 排序,则集群成员的顺序将反映这一点。

# Order data frame by dates if needed
# df <- df[order(df$event_date, df$later_event_date), ]

library(igraph)

# Create network graph
g <- graph_from_data_frame(df[grep("name$", names(df))], directed = TRUE)

您可以通过以下方式查看集群的成员资格:

split(names(V(g)), components(g)$membership)

$`1`
[1] "A" "B" "C" "G"

$`2`
[1] "D" "F" "I"

$`3`
[1] "E" "H"

创建集群成员数据框:

res <- data.frame(event = names(components(g)$membership), ind = components(g)$membership)

# Assign within cluster id
res$seq_n <- with(res, ave(event, ind, FUN = seq_along))

# Merge with dates by events
res <- merge(unique(rbind(df[1:2], setNames(df[3:4], names(df[1:2])))), res, by.y = "event", by.x = "event_name", all.y = TRUE)

# Order by index if needed
res[order(res$ind), ]

  event_name event_date ind seq_n
1          A 2020-01-01   1     1
2          B 2020-02-01   1     2
3          C 2020-03-01   1     3
7          G 2020-07-01   1     4
4          D 2020-04-01   2     1
6          F 2020-06-01   2     2
9          I 2020-09-01   2     3
5          E 2020-05-01   3     1
8          H 2020-08-01   3     2

【讨论】:

  • 感谢@27 φ 9 提供了一个非常有创意的解决方案
【解决方案2】:

我找到了一个解决方案,通过重塑数据(利用dplyrtidyr)来实现结果。不完全优雅,但它似乎工作!

# requires that the columns are first renamed as follows
df <- rename(df, event1_name = event_name, event1_date = event_date, event2_name = later_event_name, event2_date = later_event_date)

df %>%
  # only need the 'root' of each sequence
  filter(!(event1_name %in% event2_name)) %>%

  # add an identifier for each sequence
  mutate(seq_id = as.numeric(factor(event1_name))) %>%

  # draw event data into a single set of columns
  pivot_longer(cols = starts_with("event"), 
               names_to = c("event_pos", ".value"),
               names_pattern = "^event(.)_(.*)$") %>%

  # remove the duplicate rows (the roots of each sequence)
  distinct() %>%

  # add the indices of each sequence
  select(-event_pos) %>%
  group_by(seq_id) %>%
  arrange(date, .by_group = TRUE) %>%
  mutate(seq = row_number()) %>%
  ungroup()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-24
    • 1970-01-01
    • 2022-01-18
    • 2021-06-23
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    • 2017-08-08
    相关资源
    最近更新 更多