【问题标题】:R: Searching & isolating multiple first occurences in time seriesR:搜索和隔离时间序列中的多个首次出现
【发布时间】:2014-03-20 22:05:54
【问题描述】:

我正在尝试编写一个函数,该函数允许我查找给定年份中事件的多次首次出现。事件在不同的时间发生在不同的公司身上。所以一个事件可能在 1980 年第一次发生在 c 公司,然后在 1981 年发生在 b 公司。在这种情况下,我只需要找到公司 c_1980 和矩阵中的相关值。

但是,如果一个事件直到 1986 年发生在 a 公司和 1986 年也发生在 e 公司才发生,那么我需要在矩阵中找到 a_1986 和 e_1986 及其各自值的结果。

我的 (2500 * 800) 矩阵在纵轴上有 2500 个不同的事件,在横轴上有 800 个不同的 year_firm 组合。所有值都介于 0 和 10 之间(在实矩阵中,在示例中介于 0 和 2 之间),绝大多数为零。

示例数据:

av<-matrix(rep(0:2),10,40)
av[1:7,]=0 ; av[9,3:14]=0
av[,c(22,38)]=1
colnames(av)<-paste(c("a","b","c","d","e"),rep(1980:1987, each=5),sep="_")
col.av<-colnames(av)
rownames(av)<-paste("X",1:10,sep="")
row.av<-rownames(av)

我一直使用的主要公式给出了第一次出现的矩阵中的位置:

first<-max.col(av>0,"first") 

这可以很好地找到第一次出现。然而,正如数据显示的那样,有时这在同一年会多次发生(例如,第 8 行中的事件发生在 1980 年,公司 a、b、d 和 e -> 鉴于这是第 8 行变为非第 8 行的第一年-zero 我需要找到 4 个不同的值作为输出)。

到目前为止,我的代码基本上是一个补丁解决方案

avdum1<-matrix(cbind(seq(1:nrow(av)),first),nrow=nrow(av),ncol=2)
avdum2<-matrix(cbind(row.av,first),nrow=nrow(av),ncol=2)

使用 avdum1 和 avdum2 以及原始的行名和列名,然后我可以设计一个矩阵,让我在原始矩阵中第一次出现,以及第一次出现的确切值(1 或 2)以及公司-年份组合

firsttime<-matrix(cbind(row.av,col.av[first],av[avdum1]),nrow=nrow(av),ncol=3)

到目前为止一切顺利。 现在,要找到同一年的其他第一次出现,我要做的是

av[avdum1]<-0

这将原始的第一次出现置于零,然后我再次运行整个过程,然后展开第一次矩阵,将列名拆分为年份和公司名称 a、b、c、d、e,比较年,看看第二次第一次出现是否发生在同一年。如果是这样,我必须第三次重新运行整个过程,依此类推(我的真实数据集有 40 家公司)。

这变得相当麻烦,所以我想知道是否有更聪明的方法来做到这一点?可能基于该事件在矩阵中的相对位置发现阳性事件后进行本地化搜索?

最终期望的结果:

(如果您复制示例数据,则可以在生成矩阵时忽略初始警告)

对于第 1 到 7 行,结果将是 b_1984,值为 1 对于第 8 行,结果应该是 a_1980 和 1、b_1980 和 2、d_1980 和 1 和 e_1980 和 2 对于第 9 行,a_1980 与 2 对于第 10 行,b_1980 为 1,c_1980 为 2,e_1980 为 1

希望这可以澄清之前的一些问题/cmets

非常欢迎任何建议!

【问题讨论】:

  • 也许按公司拆分矩阵并在每个公司上分别运行max.col?您所说的“多次首次出现”是什么意思并不十分清楚。
  • 嗨,Carl,按公司拆分将导致每次最多 40 个事件发生(前提是每个公司在不同时间发生该事件。我的意思是“多次第一次发生”是相同的)事件(行)在同一年发生在不同的公司(a,b,c,d,e)。max.col 中的选项“first”选择第一个出现的事件,它是按字母顺序排列的,因此名称为 a,b 的公司,c 比名称为 d,e...的更可能归因于第一次出现。
  • 好的,那么如何在所有行上运行一个循环,并执行which(row[j]==max(row[j]) 来收集所有最大值? (即,甚至不用理会max.col
  • Carl,这也不起作用,因为它只会给我连续出现的最高值,而不是第一个正值。它也不会帮助找到与第一个正值在同一年的第二个正值。
  • 听起来您需要更好地定义您的标准。对于初学者来说,什么“第一次出现”?尝试发布一个小的、可重复的数据集,并准确解释您想要的输出。

标签: r search matrix time-series


【解决方案1】:

我试了一下,虽然我走的路和你的有点不同。也许,可能有一种方法可以按原样处理您的数据以给出结果(甚至可能更快),但我更喜欢使用“长”格式。长格式也可以通过“data.table”和“dplyr”等包快速处理。

首先,我将您的av 转换为以下格式的长格式:

#turn to long format
long_DF = as.data.frame(as.table(av), responseName = "value")

#tidy up
tmp = do.call(rbind.data.frame, strsplit(as.character(long_DF[[2]]), "_"))
long_DF$firm = tmp[, 1] ; long_DF$year = tmp[, 2] 
long_DF$event = long_DF[[1]] ; long_DF = long_DF[-(1:2)]

long_DF[c(1,4,5,8,15,16,20), ]
#   value firm year event
#1      0    a 1980    X1
#4      0    a 1980    X4
#5      0    a 1980    X5
#8      1    a 1980    X8
#15     0    b 1980    X5
#16     0    b 1980    X6
#20     1    b 1980   X10

从这里开始,我想会有许多不同且更有效的方法,但我只能 - 想出以下方法:

#3D array
res = xtabs(value ~ firm + year + event, long_DF)

res[, , 3, drop = F]
#, , event = X3
#
#    year
#firm 1980 1981 1982 1983 1984 1985 1986 1987
#   a    0    0    0    0    0    0    0    0
#   b    0    0    0    0    1    0    0    0
#   c    0    0    0    0    0    0    0    1
#   d    0    0    0    0    0    0    0    0
#   e    0    0    0    0    0    0    0    0

对于每个第 3 个维度,您可以搜索 1) 哪些值([行、列])大于 0 和 2)哪些值在可用的最小列中(即事件发生在较早的一年)。其实现可能是以下函数:

#function to apply to each 3rd dimension
f1 = function(x) {
      wh = which(x > 0, arr.ind = T)
      wh2 = which(wh[, "col"] == min(wh[, "col"]))
      wh3 = wh[wh2, , drop = F]
      cbind.data.frame(firm = rownames(x)[wh3[, 1]],
                       year = colnames(x)[wh3[, 2]], 
                       val = x[wh3])
} 

并将函数应用于每个 3 维;即每个事件:

ret = apply(res, 3, f1)
#ret
ans = cbind.data.frame(event = rep(names(ret), lapply(ret, nrow)), 
                       do.call(rbind.data.frame, apply(res, 3, f1)))
ans
#      event firm year val
#X1       X1    b 1984   1
#X2       X2    b 1984   1
#X3       X3    b 1984   1
#X4       X4    b 1984   1
#X5       X5    b 1984   1
#X6       X6    b 1984   1
#X7       X7    b 1984   1
#X8.1     X8    a 1980   1
#X8.2     X8    b 1980   2
#X8.3     X8    d 1980   1
#X8.4     X8    e 1980   2
#X9       X9    a 1980   2
#X10.1   X10    b 1980   1
#X10.2   X10    c 1980   2
#X10.3   X10    e 1980   1

【讨论】:

  • 嗨,Alexis,非常感谢您的详细建议。明天我会深入讨论(现在太累了),但我有一个快速的第一个问题。你在开头使用## long_DF[c(1,4,5,8,15,16,20), ] ##。你从哪里得到向量的这些值?如果我不能自动推导出它们,则意味着我需要手动遍历矩阵,这可能不可行且容易出错......
  • @simon_icl :嗯,我不确定我明白你在说什么,但如果你在谈论值“1,4,5..”,我 - 只是 - 选择了一个要显示long_DF 的行示例,因为long_DF 有很多行。如果您按原样运行代码,则使用as.data.frame.table“自动”生成long_DF,并“手动”对结果进行一些格式化(这是主观的)。顺便说一句,请原谅我主动提出您已经开始的其他建议,但我真的认为以更“通用”的格式处理数据将非常有帮助。
  • 嗨,亚历克西斯,非常感谢您的解释。我只是担心,如果我需要以某种方式找出该向量中的值,您的建议将不适用于更大的数据集。我不明白你基本上选择了一个样本来显示一些输出。请不要为提出解决方案而道歉!很高兴看到更有经验的编码人员如何通过不同的思维方式解决问题。因为我只是从 excel 和 stata 转换,所以我在 2D 矩阵中想的太多了,因为这是我唯一熟悉的东西!非常感谢!
  • @simon_icl:不客气,很高兴我能帮上忙!再次注意,我试图提出的主要观点是将您的因素(这里:公司、年份、事件)分开在一个长格式的“data.frame”中。从那时起,您可以想出许多可能的方法,让您可以轻松地继续分析。此外,还有一些包可以同时解决此类格式的内存和速度问题。
  • 嗨@alexis_laz。我终于设法实现了您的解决方案,我必须承认它运行良好,但我认为代码不准确。它似乎给了我第一次为它可以找到的第一家公司发生事件,然后在同一家公司发生相同事件的所有后续时间中大量出现。但是,它并没有给我第一次整体上发生的事件。解决它的方法是在你的'res'变量中改变公司+年份的顺序,那么它就是完美的。我无法更改它,所以想与您分享!
猜你喜欢
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 2020-06-01
  • 2018-09-23
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
相关资源
最近更新 更多