顯示具有 report 標籤的文章。 顯示所有文章
顯示具有 report 標籤的文章。 顯示所有文章

2019年5月5日 星期日

服務流量變現和數據追蹤儀表板 - 透過 Google Adsense 和 Google Analytics 建置免費的儀表板

AnalyticsXAdsense

至今執行了一年半的流量變現任務,也進入了成長瓶頸。進入成長瓶頸時,會越來越依賴數據的推敲跟追蹤。雖然翻著 GA 跟 Adsense 報表也很夠用,但如果要追蹤的項目超過二十項時,就會非常累了,非常耗時,便開始適合建置 Dashboard 一眼觀看。

好在一年前已經有想好規則,但一直沒空製作儀表板,這週末剛好擠出了點時間,就把這些想法筆記也產出個雛形:github.com/changyy/TrackingLibrary

需求:
  • 想要追蹤新舊使用者類型的價值(value per person),究竟我們可以從單一使用者身上挖出多少礦呢?
  • 想要細膩到小小功能的變現能力
  • 能否讓 GA 數據跟 Adsense 數據自動匹配
推敲方式:
  • 讓新舊使用者觀看到的廣告單元是不一樣的
  • 讓想追蹤的小小功能的廣告單元是不一樣的
  • 在 GA 數據裡,採用 event ,並且對 event report 進行設計;在 Adsense 則是在廣告名稱進行設計。後續就可以依據撈出來的資料,自動組出對應的報表。
最後產出的規則:

有兩個服務 Service1, Service2 ,其中 Service 1 共有 1 個功能,而 Service 2 有 3 個功能。假設 Service 2 的第三個功能還有兩個子功能。

Service1
Function1 [GA event report = (ec="pageview",ea="Service1",el="Function1")]
Service2
Function1 [GA event report = (ec="pageview",ea="Service2",el="Function1")]
Function2 [GA event report = (ec="pageview",ea="Service2",el="Function2")]
Function3 [GA event report = (ec="pageview",ea="Service3",el="Function3")]
SubFunction1
Google Analytics event = (ec="pageview",ea="Service3",el="Function3,SubFunction1")
Google Adsense AdName =
New User 觀看 = "[#]NU,Service2,Function3,SubFunction1"
Old User 觀看 = "[#]OU,Service2,Function3,SubFunction1"
SubFunction2 [GA event report = (ec="pageview",ea="Service3",el="Function3,SubFunction2")]


上述的高度結構後,也不是沒有缺點的,缺點就是 Adsense 的廣告單元會爆多,例如自己經手製作的廣告單元就高達兩百個,如某個想關注服務其底下共有 80 個廣告單元時,這時靠 Adsense 內建的報表,篩選了 80 個廣告單元時,這時報表很容易產不出來的。而用 GA 觀看時,因為不是用常見的網頁 ga pageview 的方式,而是靠 ga event 查看,這時也會有些不方便。上述更別說還有對應的服務開發時,需要設置規則,讓新舊使用者、不同子服務觀看不同的廣告單元和 GA event report。

最後,則是 Dashboard 要產生時,需要呼叫多次 adsense api 跟 analytics api ,而免費版使用要留意會不會踩到額度限制。

其他資訊 - 關於 TrackingLibrary 的使用:
  1. 先將程式碼中 ga_adsense_rule.json 複製至 dev.json ,程式判斷出 dev.json 就會以此為優先處理
  2. 先建立一個 Google Cloud Project,來使用 Google Adsense / Google Analytics API。
    • 切換到 "API 與服務" -> 憑證 -> OAuth 同意畫面
      • 應用程式名稱:Tracking
      • 已授權網域:changyy.org
    • 切換到 "API 與服務" -> 憑證 -> 建立憑證
      • OAuth 用戶端 ID
        • 網路應用程式:TrackingDashboard
        • 已授權的 JavaScript 來源:http://tracking.changyy.org:8000
        • 已授權的重新導向 URI:http://tracking.changyy.org:8000
    • 取得 "這是您的用戶端 ID" 並更新在 dev.json
      • 將各個 project -> google_api_project 欄位更新成 XXXXXX.apps.googleusercontent.com 即可
  3. 開啟 Google Adsense / Google Analytics API
    • API和服務 -> 資訊主頁 -> 啟用 API和服務
      • 搜尋 "Analytics API" 以及點擊啟用
      • 搜尋 "AdSense Management API" 以及點擊啟用
  4. 切換至程式碼,編輯 dev.json ,建置想要關注的 GA 專案,例如單純複製 GA only 專案內容,只修改 project -> analytics -> ga_profile_id 欄位即可
  5. 切換到專案 php/web 位置,並運行本地端 web server ,即可瀏覽
    • $ cd TrackingLibrary/php/web
    • $ php -S tracking.changyy.org:8000 ../tools/ci-routing.php
    • $ open "http://tracking.changyy.org:8000/dashboard"

2017年8月19日 星期六

[Python] 機器學習筆記 - 透過 sklearn.svm 簡易的數據分析、機器學習萬用框架 @ macOS 10.12, Python36

svm_report

幾年前有幸參加過數據分析的黑客松,但是太耍廢了 XD 當下只用統計硬幹。最近有些閒情想好好認識一下 SVM 了。目前使用它的方式很粗淺 XD 就是把一堆 feature 湊個成 array 餵進去跑,接著就有報表可以看了(當初還人工去計算 precision / recall),回想起來真是青春啊

回過頭來,程式架構如下:

import numpy as np
import pandas as pd # 假設 input 是 csv 格式

# 讀取資料中
raw = pd.read_csv("input.csv")
# 可以得知有多少欄位可以用
print(raw.columns)

# 假設所有屬性都是可以有一對一的對應,全部把他們取代成整數,此為 HASH table 用來轉換而已
LOOK_FIELD = {}

# 假設 raw 有一萬筆資料
USE_DATA_COUNT = 10000 # or raw.size

# 將 raw 資料建置成 numpy array 架構

data_input = None
data_output = None

for index, row in raw.iterrows():

data_per_row = np.empty([])

# 將有興趣的欄位(feature)抽出來使用
for field_name in [
"csv_fieldname1",
"csv_fieldname2",
]:
field_data = np.zeros(1, dtype=np.int)
if field_name not in LOOK_FIELD:
LOOK_FIELD[field_name] = {}
if row[field_name] in LOOK_FIELD[field_name]:
field_data[0] = LOOK_FIELD[field_name][row[field_name]]
else:
field_data[0] = len(LOOK_FIELD[field_name])
LOOK_FIELD[field_name][row[field_name]] = field_data[0]
data_per_row = np.append(data_per_row, field_data.reshape(1, -1))

if data_input is None:
data_input = np.zeros([USE_DATA_COUNT, data_per_row.reshape(1, -1).size], dtype=np.float)
data_input[index] = data_per_row.reshape(1, -1)


result = np.zeros([1], dtype=np.int)

output_field_name = "csv_fieldname3"

# 將 結果 的欄位轉換成數值
if output_field_name not in LOOK_FIELD:
LOOK_FIELD[output_field_name] = {}
if row[output_field_name] in LOOK_FIELD[output_field_name]:
result[0] = LOOK_FIELD[output_field_name][ row[output_field_name] ]
else:
result[0] = len(LOOK_FIELD[output_field_name])
LOOK_FIELD[output_field_name][ row[output_field_name] ] = result[0]

if data_output is None:
data_output = np.zeros([USE_DATA_COUNT, result.reshape(1, ).size], dtype=np.int)
data_output[index] = result.reshape(1, )

# 支援只使用 USE_DATA_COUNT 筆資料
if index >= USE_DATA_COUNT - 1:
break

print(data_input)
print(data_output)
print(data_input.shape)
print(data_output.shape)

from sklearn import svm, metrics

classifier = svm.SVC()

# 使用 1/5 的資料來訓練
number_of_data_to_learn = int(USE_DATA_COUNT / 5) # or int(data_output.size/5)

# start to learn
classifier.fit(data_input[:number_of_data_to_learn], data_output[:number_of_data_to_learn])

# get the result
expected = data_output[number_of_data_to_learn:]
predicted = classifier.predict(data_input[number_of_data_to_learn:])

# get the report
print("Classification report for classifier %s:\n%s\n" % (classifier, metrics.classification_report(expected, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted))


透過上述的程式架構,未來就只要把資料轉成 csv ,挑挑 feature (csv_fieldname1, csv_fieldname2) 跟 output (csv_fieldname3) 欄位就可以快速看到成果了 XD 要唬人也可以 3 分鐘就弄出點東西。