跟踪字段变化的函数

如何解决跟踪字段变化的函数

我需要一个函数(使用基本 SAS 或 RStudio)来确定某个日期的 ID 号和开始日期的原始(根)ID 号。数据集包括旧 ID、新 ID 和 ID 更改日期。示例数据:

旧ID NewID 更改日期
1 2 1/1/10
10 11 1/1/10
2 3 7/1/10
3 4 7/10/10
11 12 8/1/10

我需要知道截至 10 年 12 月 13 日的 ID 号和原始(根)ID(截至 10 年 1 月 1 日)。输出应如下所示:

OrigID LastID
1 4
10 11

然后我需要一个标志来帮助我计算在给定时间间隔(在本例中为 1/1/10 到 7/15/10)内发生变化的 OrigID 的数量。我也需要对 10 年 12 月 13 日之后的多个日期进行类似的计数。

基础 SAS 或 RStudio 中是否有可以执行此操作的函数

我研究的 SAS/R 中的功能(分层记录器、同步跟踪、序列跟踪功能)似乎不会起作用(例如,记录器、伐木工人、log4r、验证、futile.logger)

解决方法

这应该可行,我只是懒得输入正确的日期。

注意:这里假设数据按更改发生排序。

数据

df <- data.frame(
  OldID = c(1,10,2,3,11),NewID = c(2,11,4,12),ChangeDate = c(1,1,3))
df
#>   OldID NewID ChangeDate
#> 1     1     2          1
#> 2    10    11          1
#> 3     2     3          2
#> 4     3     4          2
#> 5    11    12          3

功能

process <- function(df,from,to) {
  process0 <- function(df,i = 1){
    # fetch new value
    new <- df$NewID[i]
    # check in old column
    j <- match(new,df$OldID)
    
    if(is.na(j)) {
      # if not matched,set i to next row
      i <- i + 1
    } else {
      # else we update current row with new "new" value
      df$NewID[i] <- df$NewID[j]
      # and increment the changes
      df$Changes[i] <- df$Changes[i] + 1
      # and remove obsolete row
      df <- df[-j,]
    }
    # do it all over again except if there is no next row
    if(i <= nrow(df)) process0(df,i) else df
  }
  # filter data frame
  df <- subset(df,ChangeDate >= from & ChangeDate <= to,select = c("OldID","NewID"))
  # start with 1 change per line
  df$Changes <- 1
  # run recursive function
  process0(df)
}

结果

process(df,2)
#>   OldID NewID Changes
#> 1     1     4       3
#> 2    10    11       1

reprex package (v0.3.0) 于 2021 年 6 月 9 日创建

,

SAS 中有许多工具可用于从 [OLDID,NEWID] 边表定义的图中查找连接的子图。例如来自 SAS/OR 的 PROC OPTNET。或者 %SUBGRAPHS macro created by PGStats

那么让我们首先将您的列表转换为实际数据集。

data have ;
  input OldID NewID Date :mmddyy.;
  format date yymmdd10.;
cards;
1 2 1/1/10
10 11 1/1/10
2 3 7/1/10
3 4 7/10/10
11 12 8/1/10
;

然后调用 %SUBGRAPHS() 宏来获取为每个节点计算的 CLUST(子图 id)。

%SubGraphs(have,from=oldid,to=newid,out=clusters);

现在将其与原始数据重新组合,以便获得日期。

proc sql;
  create table groups as 
    select distinct a.clust,b.*
    from clusters a
    inner join have b
      on a.node = b.oldid or a.node=b.newid
    order by a.clust,b.date
  ;
quit;

一旦您将数据中的记录与相同的子图 ID 匹配,那么查找任何日期范围的第一个/最后一个节点就很简单了:

data want ;
  do until (last.clust);
    set groups;
    by clust date;
    where '01JAN2010'd <= date <= '15JUL2010'd;
    if first.clust then origid=oldid;
  end;
  lastid=newid;
  keep origid lastid ;
run;

当然,如果您真的想按之前搜索子图的日期过滤数据,您可能会得到更多的子图,因为您可能已经消除了连接两组节点的边。

,

尝试使用 igraph,尽管可能有更简单的方法。我将从数据开始。

dat <- read.table(text="OldID   NewID   ChangeDate
1   2   1/1/10
10  11  1/1/10
2   3   7/1/10
3   4   7/10/10
11  12  8/1/10",header=TRUE)

dat$ChangeDate <- as.Date(dat$ChangeDate,format="%m/%d/%y")

设置带有属性的图形

library(igraph)
g <- graph.data.frame(dat)
V(g)$ChangeDate <- dat$ChangeDate[match(V(g)$name,dat$NewID)]
V(g)$ChangeDate[is.na(V(g)$ChangeDate)] <- -Inf

将图表子集到日期范围

g <- induced_subgraph(g,which(V(g)$ChangeDate <= as.Date("2010-07-15")))

找到起点和终点以及路径

din  <- degree(g,mode="in")
st   <- names(din[din == 0])
dout <- degree(g,mode="out")
en   <- names(dout[dout== 0])

fin  <- lapply(st,all_simple_paths,graph=g,to=en)

查询路径

t(sapply(
  unlist(fin,rec=FALSE),function(x) {
    nx <- as.numeric(names(x))
    c(OldID=head(nx,1),NewID=tail(nx,Changes=length(x)-1)
  }
))

#     OldID NewID Changes
#[1,]     1     4       3
#[2,]    10    11       1
,

另一种使用 igraph 及其函数 components 的可能性。从@thela 借用“dat”。我使用 data.table 进行数据整理步骤,但这当然也可以在 base 中完成。

library(igraph)
library(data.table)

mem = components(graph_from_data_frame(dat))$membership
setDT(dat)
dat[.(as.integer(names(mem))),on = .(OldID),mem := mem]
dat[ChangeDate <= as.Date("2010-07-15"),.(OldID = OldID[1],NewID = NewID[.N],changes = .N),by = mem]
#    mem OldID NewID changes
# 1:   1     1     4       3
# 2:   2    10    11       1
  1. 使用 graph_from_data_frame 创建图表,其中 'OldID' 和 'NewID' 列被视为边缘列表。

  2. 使用components获取图的连通分量,直接 或间接。

  3. 选择 membership 元素以获取“每个 顶点所属"

  4. 加入原始数据 on 'OldID' 的会员资格。

  5. i 中的子集日期并抓取相关数据分组 by 成员资格,即第一个“OldID”,最后一个 'NewID' 和使用 .N

    的行数
,

SAS 哈希可以跟踪 ID roots更改。可以为检测 asof 状态所需的链表遍历设置 更改

示例:

需要 ID 首次出现的根数据行。 asofs 在临时数组中指定,但也可以在加载到第三个哈希以进行 asof 迭代的外部数据集中指定。

data have; 
attrib OldID NewID length=8 ChangeDate informat=mmddyy10. format=mmddyy10.;
input OldID NewID   ChangeDate;
datalines;
.   1   3/1/09
.  10   6/1/09
1   2   1/1/10
10  11  1/1/10
2   3   7/1/10
3   4   7/10/10
11  12  8/1/10
;

data want(keep=asof origID currID changeCount);
  attrib asof format=mmddyy10. origID currID length=8;

  declare hash roots();
  roots.defineKey('NewID');
  roots.defineData('NewID','ChangeDate');
  roots.defineDone();

  declare hash changes();
  changes.defineKey('OldID');
  changes.defineData('NewID','ChangeDate');
  changes.defineDone();

  do while (not done);
    set have end=done;
    if missing(OldID)
      then roots.add();
      else changes.add();    
  end;

  array asofs (7) _temporary_ (
    '01-JAN-2009'd
    '15-MAY-2009'd
    '15-SEP-2009'd
    '15-MAR-2010'd
    '02-JUL-2010'd
    '15-JUL-2010'd
    '15-AUG-2010'd
  );

  declare hiter hi('roots');

  do index = 1 to dim(asofs);
    asof = asofs(index);

    do while (hi.next() eq 0);

      origID = newID;
      currID = .;

      do changeCount = -1 by 1 while (ChangeDate <= asof);
        currID = NewID;
        if changes.find(key:NewID) ne 0 then leave;
      end;

      output;
    end;
  end;
  stop;
run;
,

这是我对 purrr::reduce 的处理方法:

library(dplyr)

split(df,seq(nrow(df))) %>%
  purrr::reduce(~ { index <- which(.y$OldID == .x$NewID)
                    if (any(index))
                      mutate(.x,NewID = replace(NewID,index,.y$NewID))
                    else bind_rows(.x,.y) }) %>%
  transmute(OrigID = OldID,LastID = NewID)

返回:

  OrigID LastID
1      1      4
2     10     12

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?