2016-03-30 48 views
1

請在這裏找到一個長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_kn,prim_kn,pat_kn,net_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 

期望的結果 一個額外的列result在data.table與價值1 0 0 0.2 0.8 0.2 0.8 0 0 0 0 1 0 0.8 0.2

如何計算這個任何建議有效率的?

謝謝!

+0

有些東西對我來說不是很清楚,因爲'pnum == 4298558',net_kn和age_kn都有1,所以根據你的描述,沒有人比另一個大,他們應該得到0。爲什麼不是這樣? – adaien

+0

說明可能不清楚。它們都具有值1並且需要與也具有值1的下一行進行比較。如果它們相等並且爲1,則它們應該在專利 – SJDS

+0

的列中獲得值1 /正值的數量「比較僅僅是>如果這個值確實比另一個大,那麼應該把一個「點」歸因於「。他們是平等的,所以他們得到0,他們爲什麼得到1? – adaien

回答

5
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案件(可以說是正確的答案),留給讀者。

+0

真的很棒的解決方案。我甚至不知道你可以將列名添加到'data.table'中的'by'參數中。這非常整齊。同樣相當出色的你設法忽略了困難的解釋,並意識到你可以通過在一列中的行之間進行求和來達到同樣的效果。直到蝙蝠俠v超人中途,我才意識到這一點! – SJDS

+0

我的理解是否正確,這裏的'.N'等於特定變量的列數,而不是行數呢?如果是這樣,是因爲你在'by'語句中添加''var'?再次感謝! – SJDS

+0

很高興爲您提供幫助。 '.N'是每個「pnum」和給定「var」的唯一組合的行數。 – eddi

0

下面是使用dplyr一個fastish解決方案:

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