按组迭代的非连续 类 因子的欧氏距离

Euclidean distant for NON-CONSECUTIVE classes of factors iterated by groups

这个问题是这个问题的延伸。

上一个问题的相同解释也适用于此。我想根据以下公式计算每个公司基于专利 classes 的连续年份之间的欧氏距离:

其中Xi表示t年属于特定class的专利数,Yi表示上一年(t-1)属于特定class的专利数.

这里的区别是我要补充一个假设: 如果中间缺少 year/some 年 is/are,我想假设该公司一直活跃于与最近的非缺失年份相同的专利 classes。例如,在以下数据集中:

> set.seed(123)
> df <- data.table(firm = rep(c("A","B"),each=5),
               year = c(1979,1981,1981,1984,1984,1959,1960,1963,1963,1965),
               patent = sample(3800000:4200000,10,replace = FALSE),
               class = c("410","73","52","250","252","105","454","380","380","60")
               )
> df
    firm year  patent class
 1:    A 1979 3988941   410
 2:    A 1981 3934057    73
 3:    A 1981 3924021    52
 4:    A 1984 3960996   250
 5:    A 1984 4026317   252
 6:    B 1959 4165208   105
 7:    B 1960 3924506   454
 8:    B 1963 3993626   380
 9:    B 1963 3845403   380
10:    B 1965 3865160    60

公司 A 缺少 1980 年、1982 年和 1983 年。对于 1980 年,假设该公司一直在从事与 1979 年相同的技术专利:class 410。 对于 1982 年和 1983 年,假设公司一直在从事与 1981 年相同的技术专利:在 classes 73 和 52 中各有两项专利。因此,假设以这种方式表现出来:

> df
    firm year  patent class
 1:    A 1979 4108578   410
 2:    A 1980 4108578   410
 3:    A 1981 3859133    73
 4:    A 1981 3983203    52
 5:    A 1982 3859133    73
 6:    A 1982 3983203    52
 7:    A 1983 3859133    73
 8:    A 1983 3983203    52
 9:    A 1984 4158992   250
10:    A 1984 3945254   252
11:    B 1959 4077323   105
12:    B 1960 3889708   454
13:    B 1961 3889708   454
14:    B 1962 3889708   454
15:    B 1963 3830537   380
16:    B 1963 4025588   380
17:    B 1964 3830537   380
18:    B 1964 4025588   380
19:    B 1965 3944607    60

同样,对于公司 A,由于 1979 年是起始年,因此该年没有欧氏距离(应生成 NA)。前进到 1980 年,距离为零。对于 1981 年,今年 (1981) 和上一年 (1980) 的不同 classes 分别为 73、52 和 410。因此,以上公式是对这三个不同的 classes 求和(有三个不同的 'i's)。所以公式的输出将是:

为了进一步说明,解释了 1984 年的计算: 在 1984 年,A 公司在 classes 250 和 252 中共有两项专利(各一项)。前一年是 1983 年,本来是缺失的,但应用上述假设后,现在它在 classes 73 和 52 中各有两项专利。由于距离仅在连续两年之间,要计算 1984 年的距离,仅考虑 1984 年和 1983 年。因此,我们总共有四个 class(250、252、73 和 52),这意味着求和是在四个 'i' 上完成的。从第i个(class250)开始,这个class的专利总数在1984年为1,1983年为0,所以Xi等于1,Yi等于0。同理逻辑适用于 252(Xi=1,Yi=0)。现在第三个'i',即class73,专利总数在1984年为0,1983年为1,所以Xi等于0,Yi等于1。同样的逻辑适用于class 52. 因此距离由下式给出:

经过相同的计算并重复公司,最终输出应为:

> df
    firm year  patent class  El_Dist
 1:    A 1979 4108578   410       NA
 2:    A 1980 4108578   410 0.000000
 3:    A 1981 3859133    73 1.224745
 4:    A 1981 3983203    52 1.224745
 5:    A 1982 3859133    73 0.000000
 6:    A 1982 3983203    52 0.000000
 7:    A 1983 3859133    73 0.000000
 8:    A 1983 3983203    52 0.000000
 9:    A 1984 4158992   250 1.000000
10:    A 1984 3945254   252 1.000000
11:    B 1959 4077323   105       NA
12:    B 1960 3889708   454 1.414214
13:    B 1961 3889708   454 0.000000
14:    B 1962 3889708   454 0.000000
15:    B 1963 3830537   380 1.118034
16:    B 1963 4025588   380 1.118034
17:    B 1964 3830537   380 0.000000
18:    B 1964 4025588   380 0.000000
19:    B 1965 3944607    60 1.118034

为了提高速度,我最好寻找 data.table 解决方案(我的原始数据包含大约 700 万行)。

非常感谢您的帮助。

扩展可以这样

df1 <- df[, lapply(.SD, list), .(firm, year)][df[,
     .(year = min(year):max(year)), firm], on = .(firm, year)]
df1[, grp := cumsum(sapply(patent, Negate(is.null))), .(firm)]
df1[,  c('patent', 'class') := list(patent[1], class[1]), .(firm, grp)]
df1[, .(patent = unlist(patent), class = unlist(class)), .(firm, year)]

-输出

#     firm year  patent class
# 1:    A 1979 3988941   410
# 2:    A 1980 3988941   410
# 3:    A 1981 3934057    73
# 4:    A 1981 3924021    52
# 5:    A 1982 3934057    73
# 6:    A 1982 3924021    52
# 7:    A 1983 3934057    73
# 8:    A 1983 3924021    52
# 9:    A 1984 3960996   250
#10:    A 1984 4026317   252
#11:    B 1959 4165208   105
#12:    B 1960 3924506   454
#13:    B 1961 3924506   454
#14:    B 1962 3924506   454
#15:    B 1963 3993626   380
#16:    B 1963 3845403   380
#17:    B 1964 3993626   380
#18:    B 1964 3845403   380
#19:    B 1965 3865160    60

编辑:澄清后更新

这是一个主要(虽然不完全)向量化的方法 'implicit expansion':

foo = function(x, y) {
  sqrt(sum((x - y)^2)) / (sqrt(sum(x^2)) * sqrt(sum(y^2)))
}

bar = function(x, y) {
  y = unlist(y, use.names = FALSE)
  vals = union(x, y)
  list(
    x = sapply(vals, function(v) sum(x == v)),
    y = sapply(vals, function(v) sum(y == v))
  )
}

x = df[, .(prev_class = list(class)), by = .(year, firm)]

df[x, 
   on = .(firm, year > year), 
   prev_class := i.prev_class]

df[, dist :=  {
  temp = bar(class, prev_class[1L])
  foo(temp$x, temp$y)
}, by = .(firm, year)]

df
#     firm year  patent class prev_class     dist
#  1:    A 1979 3988941   410                 Inf
#  2:    A 1981 3934057    73        410 1.224745
#  3:    A 1981 3924021    52        410 1.224745
#  4:    A 1984 3960996   250      73,52 1.000000
#  5:    A 1984 4026317   252      73,52 1.000000
#  6:    B 1959 4165208   105                 Inf
#  7:    B 1960 3924506   454        105 1.414214
#  8:    B 1963 3993626   380        454 1.118034
#  9:    B 1963 3845403   380        454 1.118034
# 10:    B 1965 3865160    60    380,380 1.118034

原答案:

要使用“隐式扩展”计算距离,您可以使用以下方法。但是,我的结果与 OP 在 1963 年和 1965 年对公司 B 的预期产出不同。我不清楚 OP 如何计算这些结果。

foo = function(x, y) {
  sqrt(sum((x - y)^2)) / (sqrt(sum(x^2)) * sqrt(sum(y^2)))
}

bar = function(x, y) {
  y = unlist(y, use.names = FALSE)
  vals = union(x, y)
  list(
    x = as.integer(vals %in% x), 
    y = as.integer(vals %in% y)
  )
}

x = df[, .(prev_class = list(unique(class))), by = .(year, firm)]

df[x, 
   on = .(firm, year > year), 
   prev_class := i.prev_class]

df[, dist :=  {
  temp = bar(class, prev_class)
  foo(temp$x, temp$y)
}, by = .(firm, year)]

df
#     firm year  patent class prev_class     dist op_expected
#  1:    A 1979 3988941   410                 Inf          NA
#  2:    A 1981 3934057    73        410 1.224745    1.224745
#  3:    A 1981 3924021    52        410 1.224745    1.224745
#  4:    A 1984 3960996   250      73,52 1.000000    1.000000
#  5:    A 1984 4026317   252      73,52 1.000000    1.000000
#  6:    B 1959 4165208   105                 Inf          NA
#  7:    B 1960 3924506   454        105 1.414214    1.414214
#  8:    B 1963 3993626   380        454 1.414214    1.118034
#  9:    B 1963 3845403   380        454 1.414214    1.118034
# 10:    B 1965 3865160    60        380 1.414214    1.118034

不是答案,而是 提供的答案的扩展。

以下是阻止我的修改成为最终答案的原因:

  1. 我确信有一种更简单、更优雅的方法来完成我所做的事情。
  2. 答案正确地实现了假设,但没有直接给出缺失年份的输出。当然可以先应用 的这种扩展,但也许有一种方法可以将这两个步骤整合为一个。

无论如何,这是我根据公式进行的修改:

foo = function(x, y) {
  sqrt(sum((x - y)^2)) / (sqrt(sum(x^2)) * sqrt(sum(y^2)))
  }

bar = function(x, y) {
  x = unlist(x, use.names = FALSE)
  y = unlist(y, use.names = FALSE)
  vals = c(x, y)
  xl = length(unique(x))
  yl = length(unique(y))
  ul = length(union(x,y))
  list(
    x = c(table(vals)[names(table(vals)) %in% x],rep(0,(ul-xl))), 
    y = c(rep(0,(ul-yl)),table(vals)[names(table(vals)) %in% y])
  )
  }

x1 = df[, .(prev_class = list(class)), by = .(year, firm)]
x2 = df[, .(curr_class = list(class)), by = .(year, firm)]
x1
x2
x = merge(x1,x2)

df[x, 
   on = .(firm, year > year), 
   prev_class := i.prev_class]

df[x, 
   on = .(firm, year), 
   curr_class := curr_class]

df[, dist :=  {
  temp = bar(unique(curr_class), unique(prev_class))
  foo(temp$x, temp$y)
  }, by = .(firm, year)]

df
    firm year  patent class prev_class curr_class     dist
 1:    A 1979 3988941   410                   410      Inf
 2:    A 1981 3934057    73        410      73,52 1.224745
 3:    A 1981 3924021    52        410      73,52 1.224745
 4:    A 1984 3960996   250      73,52    250,252 1.000000
 5:    A 1984 4026317   252      73,52    250,252 1.000000
 6:    B 1959 4165208   105                   105      Inf
 7:    B 1960 3924506   454        105        454 1.414214
 8:    B 1963 3993626   380        454    380,380 1.118034
 9:    B 1963 3845403   380        454    380,380 1.118034
10:    B 1965 3865160    60    380,380         60 1.118034