2017-08-19 54 views
0

我想知道是否有辦法使用apply函數做下面的矩陣人口?我已經讀過,應用比循環更有效率。出於某種原因,我與應用函數家族掙扎。嵌套for循環使用應用函數

我正在尋找填充矩陣。我將數據框中的數據用作數據總體的條件。

下面是一個數據邏輯的例子;它是簡化的,但它涵蓋了基於規則的人口的基本要素。

id_1 <- c(1, 1, 1, 1, 1, 1) 
id_2 <- c(1, 1, 2, 2, 3, 3) 
id_3 <- c(1, 2, 2, 3, 3, 4) 
amt <- c(10, 15, 20, 25, 30, 35) 

sample_data <- data.frame(id_1, id_2, id_3, amt) 

n <- length(sample_data) 

cor <- matrix(ncol = n, nrow = n) 

i <- 1 
j <- 1 

for (i in 1:n) { 
    for (j in 1:n) { 
    if (i == j) { 
     cor[i,j] = 1 
    } else if (sample_data[2][i,] == sample_data[2][j,] & sample_data[3][i,] != sample_data[3][j,]) { 
     cor[i,j] = 0 
    } else if (sample_data[2][i,] != sample_data[2][j,] & sample_data[3][i,] == sample_data[3][j,]) { 
     cor[i,j] = 0.5 
    } else { 
     cor[i,j] = 0.25 
    } 
    } 
} 

cor 

    [,1] [,2] [,3] [,4] 
[1,] 1.00 0.00 0.25 0.25 
[2,] 0.00 1.00 0.50 0.25 
[3,] 0.25 0.50 1.00 0.00 
[4,] 0.25 0.25 0.00 1.00 

回答

3

apply是不是比for循環更有效,因此,如果您正在尋找的效率,這不是一個好方法。相反,你應該使用矢量化操作。讓我們拆開你的for循環:

首先,如果他們是在對角線上,可與diag功能可以實現要素取值1:

diag(n) 
#  [,1] [,2] [,3] [,4] 
# [1,] 1 0 0 0 
# [2,] 0 1 0 0 
# [3,] 0 0 1 0 
# [4,] 0 0 0 1 

偏離對角線的項(I,J)取如果sample_data的第二列中的條目i和j不匹配,並且如果sample_data的第三列中的條目i和j匹配,則值爲0.5。這可以通過向量化outer功能來實現:

topn.2 <- head(sample_data[,2], n) 
topn.3 <- head(sample_data[,3], n) 
0.5 * (outer(topn.2, topn.2, "!=") & outer(topn.3, topn.3, "==")) 
#  [,1] [,2] [,3] [,4] 
# [1,] 0 0.0 0.0 0 
# [2,] 0 0.0 0.5 0 
# [3,] 0 0.5 0.0 0 
# [4,] 0 0.0 0.0 0 

非對角線項(I,J)取值0.25如果條目i和j匹配在任一兩列2和3或兩者都不是。再次,這可以用outer實現:

0.25 * (outer(1:n, 1:n, "!=") & (outer(topn.2, topn.2, "==") + outer(topn.3, topn.3, "==")) != 1) 
#  [,1] [,2] [,3] [,4] 
# [1,] 0.00 0.00 0.25 0.25 
# [2,] 0.00 0.00 0.00 0.25 
# [3,] 0.25 0.00 0.00 0.00 
# [4,] 0.25 0.25 0.00 0.00 

添加一切融合在一起產生了完全量化的替代for循環:

diag(n) + 
    0.5 * (outer(topn.2, topn.2, "!=") & outer(topn.3, topn.3, "==")) + 
    0.25 * (outer(1:n, 1:n, "!=") & (outer(topn.2, topn.2, "==") + outer(topn.3, topn.3, "==")) != 1) 
#  [,1] [,2] [,3] [,4] 
# [1,] 1.00 0.00 0.25 0.25 
# [2,] 0.00 1.00 0.50 0.25 
# [3,] 0.25 0.50 1.00 0.00 
# [4,] 0.25 0.25 0.00 1.00