注目の投稿

【kepler.gl】コロナ対策による人流の変化も地図上に可視化(各種メディアで報道)

kepler.glのサイト画面 kepler.glを使ってコロナ対策の効果を分析したところ、テレビ、新聞、ネットのメディアから問い合わせや報道依頼が殺到。今も、土日返上で都内や全国の人流変化を分析しています。この記事では人流変化の可視化に便利なkepler.glにつ...

ラベル クロス集計 の投稿を表示しています。 すべての投稿を表示
ラベル クロス集計 の投稿を表示しています。 すべての投稿を表示

2017年3月15日水曜日

【R:自分用】クロス集計、ロジスティック、決定木、コレスポンデンス

#ライブラリを読み込む
library(dplyr)
library(data.table)
library(tidyr)
#
library(rpart) #決定木用
library(rpart.plot) #決定木用
library(partykit) #決定木作図用
#
library(MASS) #コレスポンデンス分析用
library(factoextra) #作図用

#cross集計
dt.cross <- dt.log %>%
  group_by(user_id,name) %>%
  summarise(n=max(value)) %>%
  spread(name,n)
dt.cross[is.na(dt.cross)] <- 0 #NAを0にする

#上記クロス集計に目的変数をjoin
dt.buy_next <- dt.log_next %>%
  group_by(user_id) %>%
  summarise(count = length(user_id))
dt.for_model <- left_join(dt.cross, dt.buy_next, by = "user_id")
dt.for_model$user_id <- NULL
dt.for_model[is.na(dt.for_logit)] <- 0 #NAを0にする

#ロジスティック分析
result <- glm(count ~ .,data = dt.for_model)
summary(result)

#出力
write.csv(summary(result)$coefficients[,"Estimate"],
          "C:/logit_Estimate.csv")
write.csv(summary(result)$coefficients[,"Pr(>|t|)"],
          "C:/logit_Pvalue.csv")

#---
#決定木
#method = "class" yが質的変数 cpは破線と交わる値が理想だが目的に合わせて適時設定
result.tree <- rpart(count ~., data = dt.cross_model, method = "class",cp = 0.002)
print(result.tree)
#検証
printcp(result.tree)
plotcp(result.tree)
#
#作図
plot(as.party(result.tree))


#---
#コレスポンデンス分析
#nfは軸を意味する
result.1 <- corresp(tmp, nf=3)
#
#write results:任意の場所に書き出す
write.csv(result.1$rs,
          "C:/result_1_rs.csv")
write.csv(result.1$cs,
          "C:/result_1_cs.csv")
#
#作図
#一般的な図
#biplot(result.1, xlim = c(-0.8, 0.8), ylim = c(-0.6, 0.6))
#少し見栄えの良い図
fviz_ca_biplot(result.1) + theme_minimal(base_size = 12)
#
#寄与率
result.1.koyuti <- result.1$cor^2
sum(result.1.koyuti)
kiyoritu <- 100*result.1.koyuti / sum(result.1.koyuti)
kiyoritu

2017年3月3日金曜日

【トレジャーデータ:Presto】SQLでのクロス集計は?caseとmap_aggならどっち?表頭項目を指定しない方法は?

SQLでのクロス集計は?

SQL(Presto)では、CASE式やmap_agg関数を利用してクロス集計をする方法がある。

CASE式の例はこちらを参照(【トレジャーデータ:Presto】各ユーザの曜日別アクセス率を集計してライフスタイルに合ったアプローチをする)。

また、CASE式以外にもmap_agg関数を使う方法もある。
例えば、下記のようなテーブル(access_log)があるとする。timeはタイムスタンプ。

table:access_log
timecategoryuser_id
1488508906経済記事id2140001
1488508907経済記事id2140001
1488508908物理記事id2140002
1488508909医学記事id2140002
1488508910医学記事id2140001
1488508911文学記事id2140003
1488508912物理記事id2140002
...
...
...

そして、下記のようなコードを書く。

SELECT 

  days,

  --集計したいcategoryの項目を指定する

  COUNT(kv['経済記事']) AS "経済記事",

  COUNT(kv['医学記事']) AS "医学記事",

  COUNT(kv['物理記事']) AS "物理記事",

  COUNT(kv['文学記事']) AS "文学記事"

FROM (

    SELECT 

      TD_TIME_FORMAT(time,

        'yyyy-MM-dd','jst') AS days,

      --map集計:キーと値の重複なしペアをつくる

      map_agg(

        category,

        user_id

      ) kv

    FROM

      access_log

    GROUP BY

      TD_TIME_FORMAT(time,

        'yyyy-MM-dd','jst'),

      category,

      user_id

  )

GROUP BY

  days

このコードを実行すると、表側を日次、表頭を各記事カテゴリとするUU(ユニークユーザ数)を集計することができる。(ここで、ユニークユーザ数となる理由は、map_aggでキーと値で重複なしのペアをつくり、そのデータをもとに集計しているため)
 

time経済記事医学記事物理記事文学記事
2017-03-012527
2017-03-02675363
2017-03-0321674
.....
.....
.....

ただ、map_aggでの集計はメモリを多く使うためデータが大きい場合には適さない。実際、数千万レコード以上のデータを対象に集計をした際、メモリ不足となり集計できなかった(エラーをみると80GB以上のメモリを使っていた)。一方、CASE式で同様の集計したところ問題なくできた。

caseとmap_aggならどっち?

結論としては、CASE式。理由は、計算が速く、メモリ消費も抑えることができるため。一方、map_aggはあまり大規模データのクロス集計に適さないと言える(と、思いますがmap_aggを有効に使う方法があれば教えて頂きたいです)。

表頭項目を指定しない方法は?

case、map_aggも共に表頭項目の指定を一つ一つ記載する必要がある。そのため、項目が未知の場合や項目が膨大にある場合には対応が難しい。そこで、表頭項目を指定しなくてもクロス集計できる方法をいろいろ調べた(ネットで2日くらい探索したりTDの中の人に聞いてみた)が、残念ながら見つからなかった。どうやら、SQL以外の方法で集計するしかなさそう。。

Rでは表頭項目を指定しなくてもクロス集計できる

Rではacast(R クロス集計(acast))やspread(R 高速に大規模データのクロス集計をおこなう(tally, spread))を使えば、一つ一つ表頭項目を指定せずにクロス集計できる。特に、spreadは大規模データでも高速に処理できるため大変オススメ。


。。。SQL上で表頭項目の指定を必要としないクロス集計が簡単にできたら良いのに…
一応、TDの中の人にお願いしておきました。


map_aggの参考サイト

 

2016年8月23日火曜日

R 高速に大規模データのクロス集計をおこなう(tally, spread)

【目的】 Rで高速に大規模データのクロス集計をしたい
【方法】 tallyとspredを使う
【補足】 library(dplyr)とlibrary(tidyr)が必要

df.cross <- df.data %>%
  group_by(x, y) %>%
  tally %>%
  spread(y, n)

#データが無い場合はNAとなるため必要に応じて0にする
df.cross[is.na(df.cross)] <- 0

◇参照URL
クロス集計~公式:dplyr + tidyr = (xtabs|(f)table)
http://d.hatena.ne.jp/teramonagi/20150312/1426109245

2015年9月16日水曜日

R クロス集計(acast)

目的:Rでエクセルのピポッドテーブルのようなクロス集計をおこなう
方法:acastを使う
補足:library(reshape2)が必要

 #サンプルデータ作成
v.x1 <- c("oda","oda","oda","toyo","toyo","toyo","ie","ie","ie","ie")
v.x2 <- c("a","a","b","b","b","c","c","c","c","c")
v.x3 <- c(1000,900,800,700,600,500,400,300,200,100)
df.x <- data.frame(user_id = v.x1, item = v.x2, price =v.x3)

df.x
> df.x
   user_id item price
1      oda    a  1000
2      oda    a   900
3      oda    b   800
4     toyo    b   700
5     toyo    b   600
6     toyo    c   500
7       ie    c   400
8       ie    c   300
9       ie    c   200
10      ie    c   100

 #クロス集計
tmp <- acast(df.x, user_id ~ item, sum, value.var = "price")

tmp
> tmp
        a    b    c
ie      0    0 1000
oda  1900  800    0
toyo    0 1300  500


#補足:user_idの列を無理やり作る

df.cross <- data.frame(tmp)
write.csv(df.cross,file = "./cross.csv")
df.cross <- fread("./cross.csv") #llibrary(data.table)が必要
df.cross <- data.frame(df.cross)

df.cross
> df.cross
    V1    a    b    c
1   ie    0    0 1000
2  oda 1900  800    0
3 toyo    0 1300  500

names(df.cross)[1] <- c("user_id")

df.cross
> df.cross
  user_id    a    b    c
1      ie    0    0 1000
2     oda 1900  800    0
3    toyo    0 1300  500


追記:acastは遅いのでspreadがお勧め
R 高速に大規模データのクロス集計をおこなう(tally, spread)