Re: [問題] 依特定欄位的內容對data.table資料作分群
※ 引述《joson4921 (特務)》之銘言:
:
: - 問題:
:
: [問題類型]:
:
: 程式諮詢(我想用R 做某件事情,但是我不知道要怎麼用R 寫出來)
:
: [軟體熟悉度]:
:
: 入門(寫過其他程式,只是對語法不熟悉)
:
: [問題敘述]:
:
: 手邊有一份資料 dt1 ,裡面有幾個欄位,以下節錄部分內容:
: Stop.No TravelTime Weekend
: 1 1 ↘
: 2 1 → 當Stop.No==1, TravelTime介於[0,120],Weekend可能為True/False
: 3 1 ↗
: ...
: 666 2 ↘
: 667 2 → 當Stop.No==2, TravelTime介於[60,180],Weekend可能為True/False
: 668 2 ↗
: ...
: 1315 3 ↘
: 1316 3 → 當Stop.No==3,TravelTime介於[120,240],Weekend可能為True/False
: 1317 3 ↗
: ...
: 2017
: =========================================================================
: ※1 共2017筆資料
: ※2 Stop.No的資料為隨機1~3, 上面表列僅為示意用
: 並非正好[ 第1~665筆的Stop.No==1, 第666~1314筆==2, 第1315~2017筆==3]
: =========================================================================
: 我想做的事情是依照 Stop.No/Weekend 欄位進行分群,
: 例:
: 這2017筆資料中有322筆資料 Stop.No==1 且 Weekend=T ,
: 則將這322筆視為同一群,其餘依此類推,故應可得到6群
: 這邊參照之前板上前輩教導的方法將相同的 Stop.No 和 Weekend 取出作 group_by
: 程式碼架構如下(by dplyr):
: dt1 %>%
: group_by( Stop.No, Weekend ) %>%
: summarise( 對 group_by 出來的6群,作集群分析,詳如下述 )
: =========================================================================
: summarise() 的內容:
: 想把「上面 group_by 出來的結果(6群),每一群都再分成兩群(gr1/gr2)並找出中心」,
: 因此上網查了分群的方法,根據google,假設上述六群中的某群叫作 gr8,
: 則可透過以下程式碼將 gr8 分成兩群,並求出 gr8 的群集中心
: kmeans.result = kmeans( gr8, 2)
: gr8_result <- gr8[, centers := kmeans.result$centers[kmeans.result$cluster] ]
: =========================================================================
: 我想做的事情:
: 以本資料 dt1 為例, group_by 出來的 6群 應可透過kmeans求出 12個集群中心
: ( gr8 裡面的 centers欄位 )
: 最後將 gr8 的 centers 欄位內容加回 dt1 對應的2017筆資料列後面
: 以上敘述滿複雜的,若有敘述不清的地方歡迎提問,小弟將盡速補充
: 請求各位前輩們協助,先謝謝各位大大了
:
: [程式範例]:
:
: [環境敘述]:
:
:
: [關鍵字]:
:
:
上一篇發現做錯,先刪掉了
好讀版:http://pastebin.com/MguuwYAi
建議直接看好讀版
簡單simulation一組資料,有五個變數,兩個變數是group by的變數
另外三個是拿來分群的變數
最終的結果是把原始資料併上每個資料的cluster以及對應的center
計算時間的話,dplyr + tidyr 或是 data.table
都可以在0.1秒以內可以算完 20000個觀察值
library(dplyr)
library(tidyr)
library(pipeR)
# dplyr + tidyr
ngrp <- 2L
numSamples <- 200L
DF <- data.frame(V1 = sample(1L:3L, numSamples, TRUE), V2 = sample(1L:2L,
numSamples, TRUE),
V3 = rnorm(numSamples), V4 = rnorm(numSamples), V5 =
rnorm(numSamples))
DF %>>% group_by(V1, V2) %>>%
summarise(
oriData = list(data.frame(V3 = V3, V4 = V4, V5 = V5)),
kmeansRes = list(kmeans(data.frame(V3_center = V3, V4_center = V4,
V5_center = V5), ngrp))) %>%
rowwise %>>%
do(V1 = .$V1, V2 = .$V2, oriData = .$oriData, grps = .$kmeansRes$cluster,
centers = as.data.frame(.$kmeansRes$centers[.$kmeansRes$cluster, ])) %>>%
mutate(V1 = unlist(V1), V2 = unlist(V2)) %>>%
unnest(grps, oriData, centers)
# # A tibble: 200 × 9
# V1 V2 grps V3 V4 V5 V3_center
V4_center V5_center
# <int> <int> <int> <dbl> <dbl> <dbl> <dbl>
<dbl> <dbl>
# 1 1 1 1 1.11016253 0.02722608 0.3027893 -0.35019463
0.1903187 0.9848824
# 2 1 1 1 0.70820726 -2.19334026 0.3242983 -0.35019463
0.1903187 0.9848824
# 3 1 1 2 -0.33493165 -0.07425543 -0.6383053 -0.02633612
0.3241840 -1.0112687
# 4 1 1 2 -2.03926090 0.24728959 0.1302806 -0.02633612
0.3241840 -1.0112687
# 5 1 1 2 -0.04744358 0.20338375 -1.3591982 -0.02633612
0.3241840 -1.0112687
# 6 1 1 2 0.12768265 1.34077790 -1.4590170 -0.02633612
0.3241840 -1.0112687
# 7 1 1 2 1.08012650 1.95067610 1.3336783 -0.02633612
0.3241840 -1.0112687
# 8 1 1 2 0.85677265 0.46973309 -0.6577587 -0.02633612
0.3241840 -1.0112687
# 9 1 1 1 0.90455630 2.44301533 -1.0511750 -0.35019463
0.1903187 0.9848824
# 10 1 1 2 1.07202152 -0.05310248 -1.4048170 -0.02633612
0.3241840 -1.0112687
# # ... with 190 more rows
# data.table
library(data.table)
ngrp <- 2L
numSamples <- 200L
DT <- data.table(V1 = sample(1L:3L, numSamples, TRUE), V2 = sample(1L:2L,
numSamples, TRUE),
V3 = rnorm(numSamples), V4 = rnorm(numSamples), V5 =
rnorm(numSamples))
DT_kmeans <- DT[ , .(
oriData = list(data.table(V3, V4, V5)),
kmeansRes = list(kmeans(data.table(V3, V4, V5) %>>%
setnames(paste0(names(.), "_center")), ngrp) %>>%
{data.table(grp = .$cluster, .$centers[.$cluster, ])})),
by = .(V1, V2)]
cbind(DT_kmeans[ , .(V1, V2)][rep(1L:nrow(DT_kmeans),
sapply(DT_kmeans$oriData, nrow)), ],
rbindlist(DT_kmeans$oriData),
rbindlist(DT_kmeans$kmeansRes))
# V1 V2 V3 V4 V5 grp V3_center V4_center
V5_center
# 1: 1 1 -1.5910524 2.1274208 -1.3464532 1 0.1155321 0.9482175
0.290026606
# 2: 1 1 0.3280774 -0.1150860 -1.2363502 2 -0.1138527 -1.1174780
-0.603929772
# 3: 1 1 -0.2026653 -0.9188654 0.4275579 2 -0.1138527 -1.1174780
-0.603929772
# 4: 1 1 -0.3258952 0.3159080 1.3667256 1 0.1155321 0.9482175
0.290026606
# 5: 1 1 -0.2819986 -1.2371227 0.6597289 2 -0.1138527 -1.1174780
-0.603929772
#
---
# 196: 2 2 0.6875229 -1.4182973 -0.1774791 1 0.5244143 -0.4805122
0.084895890
# 197: 2 2 1.1732799 -0.7428654 -0.1777401 1 0.5244143 -0.4805122
0.084895890
# 198: 2 2 -1.1992074 -0.6165810 0.0421549 2 -0.8536335 0.6373769
-0.007181771
# 199: 2 2 -0.4136762 1.1002398 0.4306150 2 -0.8536335 0.6373769
-0.007181771
# 200: 2 2 -0.1929361 -0.7346460 -0.4713694 1 0.5244143 -0.4805122
0.084895890
--
R資料整理套件系列文:
magrittr #1LhSWhpH (R_Language) https://goo.gl/72l1m9
data.table #1LhW7Tvj (R_Language) https://goo.gl/PZa6Ue
dplyr(上.下) #1LhpJCfB,#1Lhw8b-s (R_Language) https://goo.gl/I5xX9b
tidyr #1Liqls1R (R_Language) https://goo.gl/i7yzAz
pipeR #1NXESRm5 (R_Language) https://goo.gl/zRUISx
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.232.184.141
※ 文章網址: https://www.ptt.cc/bbs/R_Language/M.1488727704.A.05E.html
推
03/05 23:44, , 1F
03/05 23:44, 1F
%>%是 magrittr提供的,非本來dplyr就有,原本dplyr要推%.%這個operator
結果magrittr作者做出來之後,Hadley就直接import magrittr的%>%了
只是%>%,我自己在實務上有遇到一些奇怪的問題,後來就都改用%>>%了
其實dplyr是包含了group_by, summarise, mutate, rowwise, do那些函數~~
unnest是在tidyr裡面
→
03/05 23:45, , 2F
03/05 23:45, 2F
先測試看看吧,因為你沒直接給我資料全貌,我就只好自己生了~~
就以簡潔度來說,我覺得data.table寫起來應該是最輕鬆的
只是不容易去想怎麼做,要想比較久Orz,而且後面那段copy V1,V2是參考unnest的做法
data.table做起來會需要比較多的技巧Orz,包含把kmeans結果整理成data.table...
dplyr可能做法比較直觀,但是需要掌握rowwise, do的用法才有辦法
比較起來,兩者都有利有弊,端看使用者喜歡哪一種
推
03/05 23:50, , 3F
03/05 23:50, 3F
可以把原檔放在某個免空,用csv提供,說明用節錄即可
→
03/06 00:10, , 4F
03/06 00:10, 4F
→
03/06 00:11, , 5F
03/06 00:11, 5F
→
03/06 00:13, , 6F
03/06 00:13, 6F
→
03/06 00:14, , 7F
03/06 00:14, 7F
→
03/06 00:15, , 8F
03/06 00:15, 8F
→
03/06 00:16, , 9F
03/06 00:16, 9F
是九十組沒錯,所以我的example code是產生12組center
不過你說要併回原本的資料,我就一次做完了...
要求那12組centers就只能取distinct or unique的
V1, V2, grp, V3_center, V4_center, V5_center了
推
03/06 00:49, , 10F
03/06 00:49, 10F
→
03/06 00:49, , 11F
03/06 00:49, 11F
推
03/08 03:27, , 12F
03/08 03:27, 12F
→
03/08 03:28, , 13F
03/08 03:28, 13F
DT_kmeans 看懂就可以看懂cbind了
DT_kmeans 裡面第一個部分:
oriData = list(data.table(V3, V4, V5))
其實是創一個欄位儲存list of data.table => 用來存原始資料
因為有group by所以可以想像裡面每一個data.table都會超過一個列
第二個部分:
kmeansRes = list(kmeans(data.table(V3, V4, V5) %>>%
setnames(paste0(names(.), "_center")), ngrp) %>>%
{data.table(grp = .$cluster, .$centers[.$cluster, ])}))
逐步拆解pipe來看
kmeans(data.table(V3, V4, V5) %>>%
setnames(paste0(names(.), "_center")), ngrp)
這部分就是放入一個data.table,並設定名字,去train kmeans,#cluster = ngrp
第二個pipe後面: {data.table(grp = .$cluster, .$centers[.$cluster, ])}
pipe進來的東西是kmeans的結果,所以
grp是kmeans結果中的所在cluster,那後面.$centers[.$cluster, ]就是各群的center了
解析完DT_kmeans,接下來看回cbind,第一塊:
DT_kmeans[ , .(V1, V2)][rep(1L:nrow(DT_kmeans),
sapply(DT_kmeans$oriData, nrow)), ]
第一個[]是取V1, V2欄,後面就是根據group by後各組資料的長度將V1,V2列做複製
所以最後第一塊的長度會是原始資料的長度
第二三塊就是把各組的原始資料、kmeans結果展開合併成一個data.table
最後再全部cbind起來就可以得到結果了
※ 編輯: celestialgod (36.232.184.141), 03/08/2017 20:35:22
→
03/08 22:18, , 14F
03/08 22:18, 14F
→
03/08 22:19, , 15F
03/08 22:19, 15F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 2 篇):
R_Language 近期熱門文章
PTT數位生活區 即時熱門文章