if(!require(morpheus)) install.packages('morpheus.R')
pacman::p_load(dplyr, d3heatmap)
cols = colorRamp(c('seagreen','lightyellow','red'))
# A tibble: 27 x 4
customer_state n pc cum
<chr> <int> <dbl> <dbl>
1 SP 41746 42.0 42.0
2 RJ 12852 12.9 54.9
3 MG 11635 11.7 66.6
4 RS 5466 5.50 72.1
5 PR 5045 5.07 77.2
6 SC 3637 3.66 80.8
7 BA 3380 3.40 84.2
8 DF 2140 2.15 86.4
9 ES 2033 2.04 88.4
10 GO 2020 2.03 90.5
# ... with 17 more rows
超過80%(90%)的顧客都集中在前6(10)州
C$customer_state
into I$state
via O
I = left_join(O[,1:2], C[,c(1,5)])[-2] %>% # merge state into `O`
rename(state=customer_state) %>% # use a shoter name
right_join(I) # then merge to `I`
Joining, by = "customer_id"
Joining, by = "order_id"
TPC$product_category_name_english
into I$category
via O
I = left_join(P, TPC)[,c(1,10)] %>% # merge name into `P``
rename(category = product_category_name_english) %>% # use a shorter name
right_join(I) %>% data.frame # merge into `I`
Joining, by = "product_category_name"
Joining, by = "product_id"
state
*category
MatrixX = xtabs(price ~ state + category, I) # sum(price) per cat., per st.
X = X[order(-rowSums(X)),] # arrange rows and ...
X = X[,order(-colSums(X))] # columns in decending order
💡 「矩陣」與「熱圖」
■ 依兩類別變數做分類統計,就會產生矩陣
■ 矩陣中大部分的數值常常會集中在某幾行、某幾列裡面。
■ 通常我們會將矩陣依rowSums()
和colSums()
的大小順序分別在兩個方向做排序
cbind(rank=1:nrow(X), # the ranks of states
cum.pc=100*cumsum(cum.pc=rowSums(X)/sum(X)) # cumulative percentage
)
rank cum.pc
SP 1 38.296
RJ 2 51.721
MG 3 63.401
RS 4 68.926
PR 5 73.958
SC 6 77.786
BA 7 81.553
DF 8 83.790
GO 9 85.923
ES 10 87.962
PE 11 89.890
CE 12 91.559
PA 13 92.818
MT 14 93.977
MA 15 94.858
MS 16 95.724
PB 17 96.563
PI 18 97.207
RN 19 97.822
AL 20 98.417
SE 21 98.855
TO 22 99.222
RO 23 99.561
AM 24 99.724
AC 25 99.843
AP 26 99.943
RR 27 100.000
cbind(rank=1:ncol(X), # the ranks of categories
cum.pc=100*cumsum(cum.pc=colSums(X)/sum(X)) # cumulative percentage
)
rank cum.pc
health_beauty 1 9.3885
watches_gifts 2 18.3767
bed_bath_table 3 26.1116
sports_leisure 4 33.4815
computers_accessories 5 40.2838
furniture_decor 6 45.7271
cool_stuff 7 50.4657
housewares 8 55.1817
auto 9 59.6028
garden_tools 10 63.2223
toys 11 66.8321
baby 12 69.9034
perfumery 13 72.8805
telephony 14 75.2948
office_furniture 15 77.3382
stationery 16 79.0608
computers 17 80.7239
pet_shop 18 82.3225
musical_instruments 19 83.7509
small_appliances 20 85.1729
electronics 21 86.3682
consoles_games 22 87.5428
fashion_bags_accessories 23 88.6827
construction_tools_construction 24 89.7618
luggage_accessories 25 90.8093
home_appliances_2 26 91.6545
home_construction 27 92.2743
home_appliances 28 92.8723
agro_industry_and_commerce 29 93.4133
furniture_living_room 30 93.9274
fixed_telephony 31 94.3718
home_confort 32 94.8087
air_conditioning 33 95.2191
audio 34 95.5972
small_appliances_home_oven_and_coffee 35 95.9511
books_general_interest 36 96.3006
kitchen_dining_laundry_garden_furniture 37 96.6462
construction_tools_lights 38 96.9526
construction_tools_safety 39 97.2550
industry_commerce_and_business 40 97.5509
food 41 97.7701
market_place 42 97.9818
costruction_tools_garden 43 98.1736
art 44 98.3542
fashion_shoes 45 98.5299
drinks 46 98.6972
signaling_and_security 47 98.8576
furniture_bedroom 48 99.0070
books_technical 49 99.1495
costruction_tools_tools 50 99.2681
food_drink 51 99.3813
fashion_male_clothing 52 99.4619
fashion_underwear_beach 53 99.5330
christmas_supplies 54 99.5987
tablets_printing_image 55 99.6548
cine_photo 56 99.7066
music 57 99.7516
dvds_blu_ray 58 99.7963
books_imported 59 99.8309
party_supplies 60 99.8644
furniture_mattress_and_upholstery 61 99.8970
fashio_female_clothing 62 99.9179
fashion_sport 63 99.9337
la_cuisine 64 99.9490
arts_and_craftmanship 65 99.9625
diapers_and_hygiene 66 99.9742
flowers 67 99.9825
home_comfort_2 68 99.9882
cds_dvds_musicals 69 99.9936
fashion_childrens_clothes 70 99.9979
security_and_services 71 100.0000
X = as(X[1:15, 1:32], "matrix") # keep 15 states & 32 categorie
colnames(X) = substr(colnames(X),1,12) # use shorter names
🌞 我們只要選取最前面的15行和32列就可以覆蓋95%的銷售金額
由於我們事先已經將X
矩陣的行列次序依降冪排列,我們可以以原有的次序畫出熱圖
SP
)和賣得最好的幾個品類。
💡 學習重點:
■ 極端值會嚴重干擾視覺化的效果
■ 對數轉換:在不破壞次序的前題下,有效降低極端值的影響
[,1] [,2]
[1,] 0.00 478285
[2,] 49.99 478285
因為log(0) = -Inf
,所以取對數之前我們常需要先加進去一個數值,通常我們會選用矩陣中最小的數字
熱圖工具通常都會對矩陣的行與列分別作集群分析,在這個例子裡面,「購買行為相似的州」和「顧客地理分布相似的產品」會被檢在一起,以方便我們做觀察。
由於各州的顧客數量相差很多,州間並沒有相互比較的基礎,在熱圖裡面我們也很難觀察前三大州以外的地區;為了克服這個問題,我們可以用正規化(Normalization)的方式讓每一州的總營收都等於100,也就是說,我們讓矩陣之中的每一格都代表某一品類佔某一州總購買金額的百分比,這樣我們才能夠比較各州在品類購買比重上的異同。 (這裡的「市佔率」是指每100元的消費之中購買某品類的金額,它其實應該被稱為「口袋佔有率」)
當然我們也可以做縱向正規化,藉以比較品類在各州間的銷售分佈;
但由於SP
和RJ
太突出,直接這樣做很難看出比較效果;
💡 學習重點:
■ 注意一下縱向正規化的做法,它需要做兩次轉置 t()
■ 通常熱圖的集群分析只會做在正規化的方向(因為通常另一個方向的相似性沒有實質意義)
■ 但正規化似乎並沒有解決顏色只會集中在少數幾個品類或少數幾州的問題
矩陣數值的分布很不均勻的時候,有時候可以加上一些遮罩把極端值遮去,可能會比較容易找到結構。
X[4:15,!colnames(X) %in% c("fixed_teleph","agro_industr")] %>%
t %>% {100*./rowSums(.)} %>% t %>% d3heatmap(Rowv=F, Colv=T, col=cols)
X[, !colnames(X) %in% c("health_beaut","watches_gift")] %>%
{100*./rowSums(.)} %>% d3heatmap(Rowv=T, Colv=F, col=cols)
前面說過,單方向的正規化有一個缺點,我們對一個方向(州)做正規化之後,另外一個方向(品類)的數值就失去了比較的基礎;如果我們想要在兩個方向上同時做分類和比較,我們可以把矩陣的「標準化殘差(standardized residuals)」畫成熱圖
標準化殘差 (standardized residuals):將實際值與期望值之間的差「標準化」
\[r_{i,j} = \frac{x_{i,j} - E_{i.j}}{\sqrt{E_{i,j}}}\]
表格期望值:
\(E_{i,j} = P_i \times P_j \times R, \quad P_i = R_i/R, \quad P_j = R_j/R\)
E = (rowSums(X) %o% colSums(X))/sum(X) # cells' expected value
r = (X - E)/sqrt(E) # standerdized residuals
par(mfrow=c(1,2),mar=c(4,4,2,1),cex=0.75)
hist(r) # check distribution
r[r > 100] = 100 # cap the upper bound at 100
hist(r) # check distribution
💡 『標準化殘差熱圖』的判讀:
■ 水平方向: 某一州 vs. 全國 對各品類的消費金額分佈 (占比)
□ 紅(綠)色代表該品類在該州的消費金額占比顯著高(低)於該品類在全國的消費金額占比
□ 與全國對各品類的銷售金額分佈相比 …
§ 在ES
,fixed_teleph
(small_appli
)的銷售金額占比較高(低)
§ .. (請你自己做一些練習)
§ ..
■ 垂直方向: 某一品類 vs. 所有品類 在各州間的銷售金額分佈 (占比)
□ 紅(綠)色代表該州對該品類在的購買金額占比顯著高(低)於全國對該品類的購買金額占比
□ 與所有品類在各州間的總銷售金額分佈相比 …
§ fixed_teleph
在ES
&RJ
(PR
,MG
,SP
)的銷售金額占比較高(低)
§ ..
§ ..
■ 簡單說:綜合考慮各品類間與各州間的銷售金額(邊際)分佈之後
□ 在ES
,fixed_teleph
(small_appli
)賣得相對比較好(差)
□ fixed_teleph
在ES
&RJ
(PR
,MG
,SP
)賣得相對比較好(差)
□ ..
□ ..
💡 「矩陣」與「熱圖」
■ 依兩類別變數做分類統計,就會產生矩陣
■ 熱圖是矩陣資料的視覺化工具
■ 熱圖不只是用顏色代表數值而已
■ 它可以對矩陣的欄與列做集群分析,分別將兩個類別變數之中相似的分類撿在一起
■ 對數轉換可以降低極端(離群))值的影響,讓熱圖的顏色更有區辨效果
■ 為了建立比較基礎和加強視覺效果,有時我們需要先對矩陣的欄、列或整個矩陣做轉化
💡 「比較基礎」和「數值散佈」
■ 分析其實就是做比較,而比較需要有:「比較基礎」和「可比較性」
■ 資料轉換通常是為了解決「比較基礎」和「數值散佈」這兩個問題
■ 當要比較(或視覺化)的數值之間大小相距很大的時候,可以考慮:
§ 將數值轉化為比率
§ 做對數轉換 (log10()
)
§ 設定數值範圍 (pmin()
,pmax()
)
§ 標準化 (standardization)
§ 正規化 (normalization)
§ 標準化殘差矩陣 (standardization)
💡 「正規化」和「標準化」
基準化有兩種作法:
■ 正規化(Normalization)比較重視比例,它的值是單向的(從0到1);
■ 標準化(Standardization)比較重視變異,它的值是雙向的,以0為基準、以標準差為單位
🗿 討論問題:
■ 基準化的目的是什麼?
■ 正規化和常態化的目的有什麼異同?