Google Analytics のデータをINPUT に python で、因子分析をしてみます。
試してみた結果を記載します。
前提
OS 、Python の version は以下の通りです。
-
OS
% sw_vers ProductName: Mac OS X ProductVersion: 10.13.2 BuildVersion: 17C88
-
Python
% python3 -V Python 3.6.2
参考
Python3 の因子分析のライブラリについて
検索した限り、以下2つ見つかりました。
2つを使用してみます。
-
skeatlearn の FactorAnalysis を使う
sklearn.decomposition.FactorAnalysis — scikit-learn 0.19.1 documentation -
factor_analyzer を使う
EducationalTestingService/factor_analyzer: A Python module to perform exploratory factor analysis.
入力データについて
以下項目を持つ、csvを Google Analytics から、エクスポートしてINPUTとしました。
実際に使用するデータは、ページ
、データソース
、ページビュー数
、平均ページ滞在時間
、閲覧開始数
、直帰率
としました。
- ページ (ページのURL)
- データソース (amp か、web か)
- ページビュー数
- ページ別訪問数
- 平均ページ滞在時間
- 閲覧開始数
- 直帰率
- 離脱率
- ページの価値
必要なライブラリのインストール
pandas
、skeatlearn
、factor_analyzer
をインストールします。
python3 -m pip install pandas
python3 -m pip install sklearn
python3 -m pip install factor_analyzer
入力データの読み込み、加工
入力データの読み込み、項目編集
csvファイルを読み込み、加工します。
# pandas import
import pandas as pd
# csv 読み込み
df = pd.read_csv("Analytics_20180128-20180203.csv")
# 項目削除
del df["ページ別訪問数"]
del df["離脱率"]
del df["ページの価値"]
# データソースのflgカラムの作成、データソースの項目削除
df["web"] = [ 1 if i == "web" else 0 for i in df["データソース"]]
df["amp"] = [ 1 if i == "amp" else 0 for i in df["データソース"]]
del df["データソース"]
# 直帰率を、小数点表記に変換する
df['直帰率'] = df['直帰率'].str.rstrip('%').astype('float') / 100.0
# 平均ページ滞在時間 の表記を変換する
df['平均ページ滞在時間'] = pd.to_timedelta(df['平均ページ滞在時間']).astype('timedelta64[s]').astype(int)
# ページURLをindexに設定し、カラムからは削除
df.index = df["ページ"]
del df["ページ"]
df.sort_values(by=["ページビュー数"] ,ascending=False)
ページ | ページビュー数 | 平均ページ滞在時間 | 閲覧開始数 | 直帰率 | web | amp |
---|---|---|---|---|---|---|
/blog/java-url文字列からクエリストリングを取得/ | 94 | 528 | 78 | 0.7821 | 1 | 0 |
/blog/python-requests-post-リクエスト送信時にheader-を設定する/ | 56 | 535 | 52 | 0.8654 | 1 | 0 |
/blog/google-spread-sheet-の-複数のシートのデータをスクリプトで統合マージする/ | 52 | 145 | 46 | 0.9130 | 1 | 0 |
/search?q=cache:Wt8QOKLDOBYJ:https://www.monotalk.xyz/blog/lombokのfindbugs警告を抑制する/+&cd=1&hl=ja&ct=clnk&gl=jp | 1 | 0 | 1 | 1.0000 | 1 | 0 |
341 rows × 6 columns
データの標準化
作成したデータテーブルのカラム値を標準化します。
標準化には、sklearn の StandardScaler を使います。
from sklearn.preprocessing import StandardScaler
# 標準化
sc = StandardScaler()
values_std = sc.fit_transform(df.values)
values_std
array([[ 2.58467064, 5.94160084, 3.14574038, 0.45427759, 0.48067341,
-0.46675169],
[-0.43301625, 5.02330879, -0.49545945, -2.38644223, 0.48067341,
-0.46675169],
[-0.32895808, 4.96715424, -0.49545945, 0.65013694, 0.48067341,
-0.46675169],
...,
[-0.53707442, -0.46992747, -0.49545945, 0.65013694, 0.48067341,
-0.46675169],
[-0.43301625, -0.46992747, -0.37408612, 0.65013694, 0.48067341,
-0.46675169],
[-0.53707442, -0.46992747, -0.49545945, 0.65013694, 0.48067341,
-0.46675169]])
sklearn.decomposition.FactorAnalysis で因子分析する
from sklearn.decomposition import FactorAnalysis
index_values = df.index.values
values = values_std
# plot したいので、因子数は2にする、random_state はNone(デフォルト値)
factor = FactorAnalysis(n_components=2, random_state=None).fit(values)
# 因子分析の結果?を出力
factor.components_
array([[ 0.98725411, 0.4116763 , 0.98578738, 0.04322812, 0.3206467 ,
-0.31276261],
[ 0.11817429, -0.0616083 , 0.12648898, 0.04306155, -0.93194494,
0.93431777]])
# 平均
factor.mean_
array([ 2.08370304e-17, 8.33481215e-17, 4.16740607e-17,
-4.16740607e-16, 1.35440697e-16, -5.20925759e-17])
# 共分散行列を出力
factor.get_covariance()
array([[ 1.0000519 , 0.3991486 , 0.98817038, 0.04776591, 0.20642784,
-0.19836383],
[ 0.3991486 , 1.00002621, 0.39803253, 0.01514305, 0.18941819,
-0.18631868],
[ 0.98817038, 0.39803253, 0.99997623, 0.04806055, 0.19820871,
-0.19013654],
[ 0.04776591, 0.01514305, 0.04806055, 0.99998756, -0.02627004,
0.02671303],
[ 0.20642784, 0.18941819, 0.19820871, -0.02627004, 1.00003545,
-0.97101902],
[-0.19836383, -0.18631868, -0.19013654, 0.02671303, -0.97101902,
0.99999416]])
# 精度行列を出力
factor.get_precision()
array([[ 4.27254016e+01, -2.36557247e-01, -4.20379018e+01,
-2.86957419e-02, -3.00475908e-01, 1.47157956e-01],
[ -2.36557247e-01, 1.20803168e+00, -2.20213189e-01,
-7.41847202e-05, -7.01286958e-02, 6.81899771e-02],
[ -4.20379018e+01, -2.20213189e-01, 4.25755929e+01,
-2.72843105e-02, 7.41503962e-02, -2.11924382e-01],
[ -2.86957419e-02, -7.41847202e-05, -2.72843105e-02,
1.00370920e+00, 1.92430710e-02, -1.90205991e-02],
[ -3.00475908e-01, -7.01286958e-02, 7.41503962e-02,
1.92430710e-02, 1.75627293e+01, 1.69947583e+01],
[ 1.47157956e-01, 6.81899771e-02, -2.11924382e-01,
-1.90205991e-02, 1.69947583e+01, 1.75044451e+01]])
# 対数尤度を計算
#[【統計学】尤度って何?をグラフィカルに説明してみる。 - Qiita](https://qiita.com/kenmatsu4/items/b28d1b3b3d291d0cc698) を見て理解した気になりました。
factor.score_samples(values)
array([-26.88222376, -21.17887927, -18.64562927, -15.95512399,
-11.09015412, -16.2018379 , -9.03469648, -8.38053526,
-7.5960467 , -6.98834868, -9.12641478, -5.75128567,
-6.04428732, -13.76494109, -5.1603273 , -4.8643237 ,
-8.95151992, -5.21628783, -5.66274943, -5.45219356,
-6.19236802, -4.74118053, -8.02732884, -3.74213434,
-3.73061889, -7.58573433, -7.45257518, -5.39083205,
-6.13522878, -5.13772173, -7.52599653, -3.08423632,
-22.94402411, -48.66462817, -2.98914181, -2.94775235,
-12.73806209, -3.9274978 , -4.49272897, -8.04074106,
-3.27355439, -2.88928812, -2.9552131 , -12.21994932,
-5.1309399 , -5.19823993, -8.74220578, -9.84644612,
-9.43528641, -18.57918352, -3.83164182, -2.41720592,
-3.48025055, -3.35169751, -2.38112138, -2.71525327,
-2.77548072, -2.58890443, -2.47453018, -3.76612387,
-11.55612693, -4.45319771, -4.67763028, -8.83333124,
-2.49977192, -5.28042037, -6.37894785, -3.28087184,
-12.15324351, -2.44656305, -5.06810639, -11.32097508,
-2.69906406, -8.08841751, -2.32321471, -4.52195549,
-5.02963703, -2.70801801, -2.23905223, -3.77118053,
-3.18384417, -2.647561 , -6.16621286, -7.6228201 ,
-17.08287778, -2.2414416 , -6.83780151, -2.76768739,
-2.64758064, -3.92816078, -2.80958223, -3.20695896,
-2.4588131 , -2.48254864, -2.69777797, -5.30077629,
-3.62355096, -2.35138092, -2.98566481, -4.31472279,
-3.88684676, -9.81443294, -4.86163244, -2.71380218,
-2.70771654, -6.08206004, -4.90693932, -5.84550425,
-2.44325268, -5.22006632, -2.70880726, -2.41818702,
-2.73611274, -5.32246521, -2.47357184, -5.22898078,
-5.23092185, -5.86799266, -7.57528591, -5.87101505,
-8.23142046, -3.69853499, -7.57456095, -2.75650964,
-4.90436892, -5.24108914, -2.3901433 , -3.19472757,
-2.39422975, -6.65129952, -2.74911553, -5.34346357,
-5.34561904, -5.15909496, -5.34895111, -2.36317992,
-7.57269797, -7.38537204, -7.38537204, -4.90842926,
-5.09564576, -2.75738557, -2.76077 , -2.75738557,
-2.75738557, -2.75738557, -7.57275946, -4.58243964,
-2.75738557, -3.65363545, -4.58243964, -2.9756133 ,
-2.74509334, -58.6150682 , -2.74509334, -5.35718726,
-2.75569051, -4.58243964, -2.75738557, -2.75738557,
-2.75738557, -2.75738557, -2.75738557, -2.74509334,
-5.35718726, -2.75738557, -4.58243964, -2.75738557,
-2.75738557, -4.58243964, -4.58243964, -2.74509334,
-2.80441555, -4.58243964, -2.75569051, -4.58243964,
-2.76077 , -2.76077 , -2.74509334, -2.76077 ,
-2.74509334, -7.57275946, -2.80441555, -2.76077 ,
-3.10316551, -2.75738557, -5.89549343, -2.80441555,
-2.75738557, -3.44217658, -4.58243964, -2.87602998,
-2.75738557, -5.26037821, -2.57948141, -2.74509334,
-5.35718726, -4.60001609, -4.58243964, -2.75738557,
-2.75738557, -58.6150682 , -2.74509334, -2.6324238 ,
-4.71907566, -2.76077 , -58.6150682 , -4.60001609,
-4.58243964, -2.76077 , -2.76077 , -4.58243964,
-5.26037821, -2.76077 , -2.65152588, -4.64556143,
-4.60001609, -2.75738557, -4.71907566, -2.74509334,
-2.75738557, -2.74509334, -4.16045985, -4.95001077,
-4.58243964, -3.10316551, -2.75738557, -6.35218634,
-4.58243964, -2.75738557, -4.58243964, -2.76077 ,
-4.58243964, -2.75738557, -4.58243964, -2.74509334,
-4.58243964, -4.58243964, -2.76077 , -4.71907566,
-2.75738557, -3.65363545, -2.74509334, -2.75738557,
-4.60001609, -2.76077 , -2.75738557, -2.74509334,
-3.44217658, -2.75738557, -2.74509334, -4.58243964,
-2.75738557, -4.58243964, -2.80441555, -2.74509334,
-2.74509334, -2.75738557, -4.58243964, -2.80441555,
-2.75738557, -2.75738557, -2.75738557, -2.75738557,
-2.75738557, -4.58243964, -2.57948141, -2.75738557,
-2.57684846, -2.76077 , -2.76077 , -4.58243964,
-2.75738557, -2.75738557, -3.10316551, -4.60001609,
-4.58243964, -2.57948141, -3.44217658, -2.75738557,
-2.74509334, -2.75738557, -2.76077 , -3.2586866 ,
-4.60001609, -2.75738557, -3.2586866 , -2.9756133 ,
-2.74509334, -5.26037821, -4.60001609, -2.75738557,
-2.75738557, -4.60001609, -2.75738557, -4.60001609,
-2.89409042, -2.76077 , -2.75738557, -2.74509334,
-2.75738557, -2.75738557, -2.76077 , -2.76077 ,
-3.89306321, -4.58243964, -3.63454366, -2.76077 ,
-2.75738557, -2.60113937, -4.58243964, -2.76077 ,
-2.74509334, -2.76077 , -2.80441555, -2.75738557,
-2.87602998, -5.35718726, -2.75738557, -2.75738557,
-2.74509334, -2.57948141, -2.75738557, -2.76077 ,
-2.75738557, -2.75738557, -2.76077 , -2.75738557,
-2.6750994 , -2.9756133 , -2.74509334, -2.74509334,
-3.75556402, -2.9756133 , -2.75738557, -4.58243964,
-4.58243964, -2.75738557, -2.75738557, -2.74509334, -2.75738557])
# 平均対数尤度を計算する
factor.score(values)
-5.087489145362464
X_transformed = factor.fit_transform(values)
print("* 推定ノイズ分散")
print(factor.noise_variance_)
print("* 固有ベクトル")
print(factor.components_)
print("* 反復時の対数尤度")
print(factor.loglike_)
print("* 反復回数")
print(factor.n_iter_)
* 推定ノイズ分散
[ 0.01141607 0.82675325 0.01220002 0.99626459 0.02869978 0.02922401]
* 固有ベクトル
[[ 0.98725411 0.4116763 0.98578738 0.04322812 0.3206467 -0.31276261]
[ 0.11817429 -0.0616083 0.12648898 0.04306155 -0.93194494 0.93431777]]
* 反復時の対数尤度
[-2769.6111439014703, -2532.8459135320918, -2322.1060227954972, -2132.7023670986919, -1976.0755036105688, -1861.9624988585206, -1791.7650498542228, -1756.3966117270038, -1741.8858151772272, -1736.9090900302376, -1735.4112214477689, -1734.9945834483028, -1734.8820469443217, -1734.8503220338521, -1734.8394217395453, -1734.8337985576372]
* 反復回数
16
グラフに描画する
%matplotlib inline
#プロット用のライブラリを利用
import matplotlib.pyplot as plt
import matplotlib
font = {'family': 'IPAexGothic'}
matplotlib.rc('font', **font)
plt.figure(figsize=(16,14))
plt.scatter(X_transformed[::2,0],X_transformed[::2,1])
plt.xlabel('X')
plt.ylabel('Y')
count = 0
for xy in zip(X_transformed[::2,0], X_transformed[::2,1]):
plt.annotate(index_values[count], xy=xy, textcoords='data')
count = 1+ count
出力された図から、因子を特定してみようかと思いましたが、何がなんだかよくわからず..断念します。
factor_analyzer を使って、因子分析する
続いて、factor_analyzer
を使います。
R の factanal
関数を使用した際に得られる戻り値を取得することができます。
個人的にはfactanal
の出力がわかりやすく思えたので、factor_analyzer
もわかりやすいです。
from factor_analyzer import FactorAnalyzer
# 標準化したデータをコピーして新たにdataframeを作成する
df_std = pd.DataFrame(values_std)
df_std.index = df.index
df_std.columns = df.columns
# 因子数は2 を設定する
fa = FactorAnalyzer()
fa.analyze(df_std, 2, rotation=None)
# 因子負荷量を出力
fa.loadings
Factor1 | Factor2 | |
---|---|---|
ページビュー数 | 0.828100 | 0.561866 |
平均ページ滞在時間 | 0.395504 | 0.128913 |
閲覧開始数 | 0.810686 | 0.559416 |
直帰率 | -0.015634 | 0.040196 |
web | 0.718495 | -0.690493 |
amp | -0.699067 | 0.676665 |
# 独自性を出力
fa.get_uniqueness()
Uniqueness | |
---|---|
ページビュー数 | -0.001444 |
平均ページ滞在時間 | 0.826958 |
閲覧開始数 | 0.029841 |
直帰率 | 0.998140 |
web | 0.006985 |
amp | 0.053429 |
平均ページ滞在時間と、直帰率 は独自性が強い(2因子の影響を受けていない)ということになるのかと思います。
# 寄与度、寄与率、累積寄与率の出力
fa.get_factor_variance()
Factor1 | Factor2 | |
---|---|---|
SS Loadings | 2.504560 | 1.581530 |
Proportion Var | 0.417427 | 0.263588 |
Cumulative Var | 0.417427 | 0.681015 |
# 固有値を出力
fa.get_eigenvalues()
( Original_Eigenvalues
0 2.506915
1 1.583361
2 0.227129
3 -0.001580
4 -0.007516
5 -0.222220, Common_Factor_Eigenvalues
0 2.506915
1 1.583361
2 0.227129
3 -0.001580
4 -0.007516
5 -0.222220)
ドキュメントを読む限り、factor_analyzer
は、因子分析の結果?の2次元配列は取得できなさそうです。
因子負荷量や、独自性の出力が行えるので、ざっくりデータを見る際は、factor_analyzer
を使い、その後、グラフにプロットする場合は、FactorAnalysis
、という使い分けをしようかと思います。
以上です。
コメント