【问题标题】:Apply function across multiple columns跨多个列应用函数
【发布时间】:2016-03-30 11:01:02
【问题描述】:

请在此处找到我正在使用的长 data.table 的一小部分

dput(dt)
structure(list(id = 1:15, pnum = c(4298390L, 4298390L, 4298390L, 
    4298558L, 4298558L, 4298559L, 4298559L, 4299026L, 4299026L, 4299026L, 
    4299026L, 4300436L, 4300436L, 4303566L, 4303566L), invid = c(15L, 
    101L, 102L, 103L, 104L, 103L, 104L, 106L, 107L, 108L, 109L, 87L, 
    111L, 2L, 60L), fid = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 2L, 
    4L, 4L, 4L, 4L, 3L, 3L, 2L, 2L), .Label = c("CORN", "DowCor", 
    "KIM", "Texas"), class = "factor"), dom_kn = c(1L, 0L, 0L, 0L, 
    1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 1L), prim_kn = c(1L, 
    0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L), pat_kn = c(1L, 
    0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L), net_kn = c(1L, 
    0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 1L), age_kn = c(1L, 
    0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L), legclaims = c(5L, 
    0L, 0L, 2L, 5L, 2L, 5L, 0L, 0L, 0L, 0L, 5L, 0L, 5L, 2L), n_inv = c(3L, 
    3L, 3L, 2L, 2L, 2L, 2L, 4L, 4L, 4L, 4L, 2L, 2L, 2L, 2L)), .Names = c("id", 
    "pnum", "invid", "fid", "dom_kn", "prim_kn", "pat_kn", "net_kn", 
    "age_kn", "legclaims", "n_inv"), class = "data.frame", row.names = c(NA, 
    -15L))

我希望在 5 个不同的列中应用经过调整的大于比较

在每个pnum(专利)中,有多个invid(发明人)。我想将每行dom_knprim_knpat_knnet_knage_kn 列的值与具有相同pnum 的其他行中的值进行比较。比较只是>,如果该值确实大于另一个,则应归为一个“点”。

所以对于第一行pnum == 4298390invid == 15,你可以看到五列的值都是1,而invid == 101 | 102的值都是零。这意味着如果我们单独比较(大于?)第一行中的每个值与第二行和第三行中的每个单元格,总和将为 10 分。在每一次比较中,第一行的值更大,有 10 次比较。 比较次数是由设计5 * (n_inv -1) 设计的。 我正在寻找的第 1 行的结果应该是 10 / 10 = 1

对于pnum == 4298558net_knage_kn 列在两行中的值都为 1(对于 invid 103 和 104),因此每个应该得到 0.5 分(如果有三个具有价值的发明者1,每个人都应该得到0.33分)。 pnum == 4298558 也是如此。

对于下一个pnum == 4299026,所有值都为零,因此每次比较都应该得到 0 分。

因此请注意区别:存在三种不同的二元比较

1 > 0 --> assign 1
1 = 1 --> assign 1 / number of positive values in column subset
0 = 0 --> assign 0

想要的结果 data.table 中有一个额外的列result,其值为1 0 0 0.2 0.8 0.2 0.8 0 0 0 0 1 0 0.8 0.2

关于如何有效地计算这个有什么建议吗?

谢谢!

【问题讨论】:

  • 我不清楚,对于pnum==4298558,net_kn 和age_kn 都有1,所以没有一个大于另一个,根据你的描述,它们应该得到0。为什么不是这样?
  • 描述可能不清楚。它们都具有值 1,需要与下一行也具有值 1 进行比较。如果它们相等且为 1,则它们的值应为 1/专利中列中正值的数量
  • "比较简单>,如果值确实大于另一个,则应归为一个"点"。他们是相等的,所以他们得到 0,为什么他们得到 1?
  • 好的,我需要重新构建它。如果在同一列和同一专利中,多个值的值为 1,则分配的值不为零。它需要是 1 除以非零值的数量
  • 那些列只会取值 1 或 0?

标签: r data.table


【解决方案1】:
vars = grep('_kn', names(dt), value = T)

# all you need to do is simply assign the correct weight and sum the numbers up
dt[, res := 0]
for (var in vars)
  dt[, res := res + get(var) / .N, by = c('pnum', var)]

# normalize
dt[, res := res/sum(res), by = pnum]
#    id    pnum invid    fid dom_kn prim_kn pat_kn net_kn age_kn legclaims n_inv res
# 1:  1 4298390    15   CORN      1       1      1      1      1         5     3 1.0
# 2:  2 4298390   101   CORN      0       0      0      0      0         0     3 0.0
# 3:  3 4298390   102   CORN      0       0      0      0      0         0     3 0.0
# 4:  4 4298558   103 DowCor      0       0      0      1      1         2     2 0.2
# 5:  5 4298558   104 DowCor      1       1      1      1      1         5     2 0.8
# 6:  6 4298559   103 DowCor      0       0      0      1      1         2     2 0.2
# 7:  7 4298559   104 DowCor      1       1      1      1      1         5     2 0.8
# 8:  8 4299026   106  Texas      0       0      0      0      0         0     4 NaN
# 9:  9 4299026   107  Texas      0       0      0      0      0         0     4 NaN
#10: 10 4299026   108  Texas      0       0      0      0      0         0     4 NaN
#11: 11 4299026   109  Texas      0       0      0      0      0         0     4 NaN
#12: 12 4300436    87    KIM      1       1      1      1      1         5     2 1.0
#13: 13 4300436   111    KIM      0       0      0      0      0         0     2 0.0
#14: 14 4303566     2 DowCor      1       1      1      1      1         5     2 0.8
#15: 15 4303566    60 DowCor      1       0      0      1      0         2     2 0.2

处理上述NaN 案例(可以说是正确答案),留给读者。

【讨论】:

  • 确实是一个很棒的解决方案。我什至不知道您可以将列名添加到data.table 中的by 参数。这很整洁。同样非常出色的是,您设法忽略了困难的解释,并意识到您可以通过对列中的行求和来实现相同的目的。我直到蝙蝠侠大战超人的一半才意识到这一点!
  • 据我了解,这里的.N 是否正确等于特定变量的列和,而不是行数的计数?如果是这样,这是因为您在by 语句中添加了'var?再次感谢!
  • 很高兴为您提供帮助。 .N 是“pnum”和给定“var”的每个唯一组合的行数。
【解决方案2】:

这是使用dplyr 的快速解决方案:

library(dplyr)
dt %>%
 group_by(pnum) %>% # group by pnum
 mutate_each(funs(. == max(.) & max(.) != 0), ends_with('kn')) %>%
 #give a 1 if the value is the max, and not 0. Only for the column with kn
 mutate_each(funs(. / sum(.)) , ends_with('kn')) %>%
 #correct for multiple maximums
 select(ends_with('kn')) %>%
 #remove all non kn columns
 do(data.frame(x = rowSums(.[-1]), y = sum(.[-1]))) %>%
 #make a new data frame with x = rowsums for each indvidual
 # and y the colusums
 mutate(out = x/y)
 #divide by y (we could just use /5 if we always have five columns)

out 列中给出您想要的输出:

Source: local data frame [15 x 4]
Groups: pnum [6]

      pnum     x     y   out
     (int) (dbl) (dbl) (dbl)
1  4298390     5     5   1.0
2  4298390     0     5   0.0
3  4298390     0     5   0.0
4  4298558     1     5   0.2
5  4298558     4     5   0.8
6  4298559     1     5   0.2
7  4298559     4     5   0.8
8  4299026   NaN   NaN   NaN
9  4299026   NaN   NaN   NaN
10 4299026   NaN   NaN   NaN
11 4299026   NaN   NaN   NaN
12 4300436     5     5   1.0
13 4300436     0     5   0.0
14 4303566     4     5   0.8
15 4303566     1     5   0.2

NaN 来自没有获胜者的组,使用例如:

x[is.na(x)] <- 0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-11
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多