2016-12-15 40 views
2

我在R中使用data.tables工作。我有以下data.table編碼一組點與座標A,B,C,D和索引編碼點屬於一個集。R:data.table比較行集

library(data.table) 

     A B C D set 
    1: 0 0 0 0 1 
    2: 1 0 1 0 2 
    3: 1 1 1 0 2 
    4: 0 1 0 0 2 
    5: 1 0 1 1 2 
    6: 0 1 0 0 3 
    7: 1 1 0 0 3 
    8: 0 0 1 0 4 
    9: 1 0 1 0 4 
    10: 0 1 0 1 4 
    11: 0 0 0 0 5 
    12: 1 0 0 0 5 
    13: 1 1 1 0 5 
    14: 1 1 1 1 5 

dt = setDT(structure(list(A = c(0L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 
0L, 1L, 1L, 1L), B = c(0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 1L, 
0L, 0L, 1L, 1L), C = c(0L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L, 
0L, 0L, 1L, 1L), D = c(0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 
0L, 0L, 0L, 1L), set = c(1L, 2L, 2L, 2L, 2L, 3L, 3L, 4L, 4L, 
4L, 5L, 5L, 5L, 5L)), .Names = c("A", "B", "C", "D", "set"), row.names = c(NA, 
-14L), class = "data.frame")) 

我有另一個表編碼例如每套的概率。

set  mass 
1: 1 0.27809187 
2: 2 0.02614841 
3: 3 0.36890459 
4: 4 0.28975265 
5: 5 0.03710247 

wt = setDT(structure(list(set = 1:5, mass = c(0.27809187, 0.02614841, 0.36890459, 
0.28975265, 0.03710247)), .Names = c("set", "mass"), row.names = c(NA, 
-5L), class = "data.frame")) 

我想創建一個程序來創建一個子空間的投影例如,光盤。 (注意1,4,6,7,11,12在這種情況下,該一致的原始點,組1和3是在該子空間中的相同,以及套2和5

unique(dt[,c("C","D", "set")]) 
> C D set 
1: 0 0 1 
2: 1 0 2 
3: 0 0 2 
4: 1 1 2 
5: 0 0 3 
6: 1 0 4 
7: 0 1 4 
8: 0 0 5 
9: 1 0 5 
10: 1 1 5 

並確定同一組,只保留獨特的人,總結了相應的羣衆即在此情況下:

> C D set 
1: 0 0 1 
2: 1 0 2 
3: 0 0 2 
4: 1 1 2 
5: 1 0 4 
6: 0 1 4 

    set  mass 
1: 1 0.6469965 % set 1 + set 3 
2: 2 0.06325088 % set 2 + set 5 
3: 4 0.36890459 

感謝您的想法

回答

2

與Frank的概念類似,我們可以將每組的二進制值映射到x * 2^((length(x) - 1):0)的小數。子集,也爲 「C」 和 「d」,我們得到:

coords = c("C", "D") 
d = data.frame(set = dt$set, 
      val = Reduce("+", Map("*", list(dt$C, dt$D), 2^((length(coords) - 1):0)))) 
d 

然後,我們可以組遵循同樣的想法套相同:

tab = table(d$val, d$set) > 0L ## `table(d) > 0` to ignore the duplicates 
gr = colSums(tab * (2^((nrow(tab) - 1):0))) 
gr 
# 1 2 3 4 5 
# 8 11 8 6 11 

## another (pre-edit) alternative with unnecessary overhead 
#gr = cutree(hclust(dist(table(d) > 0L)), h = 0) 
#gr       
#1 2 3 4 5 
#1 2 1 3 2 

和聚集在此基礎上組:

rowsum(wt$mass[match(names(gr), wt$set)], gr, reorder = FALSE) 
#   [,1] 
#8 0.64699646 
#11 0.06325088 
#6 0.28975265 
+0

而不是'list(dt $ C,dt $ D)',也許你的意思是'dt [coords]'(用'coords'而不是手動再次輸入)? – Frank

+0

@Frank:最初,我的意思是'dt [,coords]',但我需要「with = FALSE」,所以我使用list(dt $ C,dt $ D)'。 'dt [coords]'正在給出一個_「當我是data.table(或字符向量)時,加入的列必須是...」_錯誤 - 也許我沒有最新版本 –

+1

哦對了,我忘了data.frame vs data.table的東西;我應該說with = FALSE的方式。順便說一句,最新的CRAN版本確實允許使用'dt [,coords]''仍然需要'dt [,c(「C」,「D」)]',但= = FALSE。據新聞報道,'dt [,..coords]將會起作用。 https://github.com/Rdatatable/data.table/blob/master/NEWS.md – Frank

2

一個有點笨拙的選項:爲每個組一個唯一的字符串,然後

coords = c("C", "D") 
gDT = setorder(unique(dt[,c(coords, "set"), with=FALSE]))[, 
    .(s = paste(do.call(paste, c(.SD, .(sep="_"))), collapse=".")) 
, by=set, .SDcols = coords][, 
    g := .GRP 
, by=s][] 

# set   s g 
# 1: 1   0_0 1 
# 2: 2 0_0.1_0.1_1 2 
# 3: 3   0_0 1 
# 4: 5 0_0.1_0.1_1 2 
# 5: 4  0_1.1_0 3 

gDT[wt, on=.(set), mass := i.mass ] 
gDT[, .(set = first(set), mass = sum(mass)), by=g] 

# g set  mass 
# 1: 1 1 0.64699646 
# 2: 2 2 0.06325088 
# 3: 3 4 0.28975265 

評論

  • 您可以通過在最後一行鏈上[, g := NULL][]擺脫g的。

  • setorder只是對數據進行排序,以便唯一的字符串在相同的集合集中表現出相同的結果。

  • 分組firstsum操作進行了優化,你可以看到,如果你添加verbose = TRUE到最後一行,像gDT[, .(set = first(set), mass = sum(mass)), by=g, verbose=TRUE]