2015-06-08 38 views
4

我有一個user_id - category對的表。用戶可以分爲多個類別。我試圖爲每個可能的結果計算交叉類別。在R或MySQL中創建交叉表

example results

我想結果是這個樣子,顯示計數橫:即誰是A類,也C類用戶等

我的原始數據的結構是這樣的數類別:

example results

怎麼能在這個R或MySQL的實現呢?數據非常大。

這裏的是樣本數據:

data <- structure(list(category = structure(c(1L, 2L, 2L, 1L, 3L, 3L, 
2L, 1L, 3L, 2L, 2L, 2L, 3L, 1L, 1L, 3L), .Label = c("A", "B", 
"C"), class = "factor"), user_id = c(464L, 345L, 342L, 312L, 
345L, 234L, 423L, 464L, 756L, 756L, 345L, 345L, 464L, 345L, 234L, 
312L)), .Names = c("category", "user_id"), class = "data.frame", row.names = c(NA, 
-16L)) 

任何代碼段上的方法,函數,或包建議的想法,將不勝感激。謝謝! -John

+0

您能給出樣本數據的預期輸出嗎?我假設它不是第二個數字,因爲它甚至不是對稱的。 – josliber

+0

Hi @josiber,你是對的 - 第二個數字只是結果的一個例子。我無法弄清楚如何得到任何結果,直到找到解決這個問題的辦法。雖然這個功能只是用戶數量。希望有所幫助。 –

+1

既然你已經發布了一個16行的例子,我想你可以手工計算它。請這樣做,併發布預期的輸出結果,因爲在這樣做之前,您沒有可重複的示例。 – josliber

回答

2

在R,I將由用戶通過首先分裂處理這個數據,計算類別該用戶的所有唯一對,然後分組在一起:

data$category <- as.character(data$category) 
(combos <- do.call(rbind, tapply(data$category, data$user_id, function(x) { 
    u <- unique(x) 
    if (length(u) > 1) t(combn(u, 2)) 
    else NULL 
}))) 
#  [,1] [,2] 
# [1,] "C" "A" 
# [2,] "A" "C" 
# [3,] "B" "C" 
# [4,] "B" "A" 
# [5,] "C" "A" 
# [6,] "A" "C" 
# [7,] "C" "B" 

的最後一步是製表的對,它可以在河的table函數來完成,我們將實際使用table兩次(A,b)和(b,a)爲一類每個配對和b捕捉:基於

table(combos[,1], combos[,2]) + table(combos[,2], combos[,1]) 
#  A B C 
# A 0 1 4 
# B 1 0 2 
# C 4 2 0 
+0

對不起,延遲迴復 - 我試過了一個樣本數據集,它效果很好。我不得不使用SQL解決方案,因爲我被300M記錄卡住了。我沒有意識到最終的數據集會很大!我不知道如何使用與R一樣大的數據。無論如何,謝謝,謝謝,謝謝。 –

0

在MySQL中,你可以很容易地在一個三欄格式做到這一點:

select a.category, b.category, count(*) 
from pairs a join 
    pairs b 
    on a.user_id = b.user_id 
group by a.category, b.category; 

生產表作爲基質在SQL挑戰,除非你知道所有的列名。否則,你需要一個動態數據透視表(谷歌:「動態數據透視表」)。對於數據庫中的大多數用途,三列格式是優選的。

1

我提供的樣本數據其實並不是t hink @josilber提供的R解決方案是正確的,但由於缺乏所需的示例解決方案,我可能會錯誤。我認爲你可以用igraph及其數據的雙向網絡表示來做到這一點,但是這對於更大的數據/類別集可能是低效的。作爲替代使用的數據的稀疏矩陣表示中的R相對有效的計算可以做這樣的:

library('Matrix') 
mat <- spMatrix(nrow=length(unique(data$category)), 
    ncol=length(unique(data$user_id)), 
    i = as.numeric(factor(data$category)), 
    j = as.numeric(factor(data$user_id)), 
    x = rep(1, length(as.numeric(data$category))) 
) 
rownames(mat) <- levels(factor(data$category)) 
colnames(mat) <- levels(factor(data$user_id)) 
mat 

#mat_row <- mat %*% t(mat) 

## Based on @user20650's comment this is even more efficient than 
## the multiplication above: 
mat_row <- tcrossprod(mat) 

此我認爲產生以下正確的輸出基於上述採樣數據:

> mat_row 
3 x 3 sparse Matrix of class "dgCMatrix" 
    A B C 
A 7 3 5 
B 3 12 4 
C 5 4 5 
+1

另一個alt ...'tcrossprod(table(dat))' – user20650

+1

肯定!但是如果你有很多用戶/類別(比如數百萬),你可能會在稀疏矩陣表示之前遇到內存問題。但是對於這種方法,在更可管理的數據大小上肯定是+1! –

+1

也像josibers解決方案(除了對角線)'tcrossprod(!! table(dat))' – user20650

0

您可以使用dplyr創建所有唯一對的列表,並使用crossprod來統計一對類別共有的用戶數量。

> library(dplyr) 
> data <- data %>% group_by(user_id, category) %>% summarize(records = sign(n())) 
> crossprod(table(data$user_id, data$category)) 

    A B C 
    A 4 1 4 
    B 1 4 2 
    C 4 2 5