EDA of Google Analytics Data
kaggle의 Google Analytics Sample dataset으로 Bigquery와 연결해 보자.
Nov 17, 2023
* DILLON MYRICK의 NOTEBOOK을 필사한 내용입니다.
Goal 주요 목표분석 자료 기간분석 과정SQL | EDA of Google Analytics Data1. 데이터 확인2. Make Our Goals Concrete3. Explore and Analyze Data1. Most Popular Pages2. Browser and Device3. Traffic Type and Quality4. Identify Conversion Path and Possible Bottlenecks5. Identify Best-Selling Product Categories and Forecast Demand
Goal
The goal of this project is to act as a Data Analyst for the Google Merchandise Store, and analyze Google Analytics data from Bigquery using SQL.
이 프로젝트의 목표는 Google Merchandise Store의 데이터 분석가 역할을 수행하고 SQL을 사용하여 Bigquery에서의 Google Analytics 데이터를 분석하는 것입니다.
주요 목표
- 현재 사이트 트래픽의 구성 이해
- 사용자의 흐름 및 전환 경로 이해
- 제품 수요 예측
분석 자료 기간
2016/08/01 - 2017/08/01
분석 과정
- 데이터 추출 및 내용 확인
- 목표를 구체화하기
- 데이터 탐색 및 분석
- 통찰력 시각화 및 결과 해석
SQL | EDA of Google Analytics Data
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt
1. 데이터 확인
- 데이터에 대한 정보는 이 링크에 자세히 설명되어 있다.
- 빅쿼리와 연동해서 데이터를 보기 위해 관련 라이브러리를 설치 라이브러리 깃허브
pip install --upgrade google-cloud-bigquery
- 설치 후 불러오면 인증을 하라고 에러 메시지가 뜬다.
from google.cloud import bigquery client = bigquery.Client() dataset_ref = client.dataset('google_analytics_sample', project = 'bigquery-public-data') dataset = client.get_dataset(dataset_ref)
해당 링크에 들어가서 설치하면 콘솔창이 뜨는데 저대로 입력하면 구글 로그인 페이지가 열린다.
인증이 되었다면 다시 vscode로 돌아와서 재실행
from google.cloud import bigquery client = bigquery.Client() dataset_ref = client.dataset('google_analytics_sample', project = 'bigquery-public-data') dataset = client.get_dataset(dataset_ref)
그러자 이런 오류가 떴는데… 프로젝트 설정을 안 해줘서 그런 듯하다,,?
when Ibigquery.Client(project="My Valid Project")
then the call succeeds.
검색해보니 이런 해결 방안을 줌
그냥 프로젝트명 작성하면 해결 !
from google.cloud import bigquery # client 생성 client = bigquery.Client(project = "프로젝트 ID 복붙") # dataset reference 생성 dataset_ref = client.dataset('google_analytics_sample', project = 'bigquery-public-data') dataset = client.get_dataset(dataset_ref)
⭐ 혹시나 빅쿼리 사용이 처음이라 회원가입부터 해야 한다면,
오류는 해결됐지만 경고 메시지가 뜬다. ㅎ ㅎ ㅎ ㅎ ㅎ ㅎ ㅎ
UserWarning: Your application has authenticated using end user credentials from Google Cloud SDK without a quota project. You might receive a "quota exceeded" or "API not enabled" error. See the following page for troubleshooting: https://cloud.google.com/docs/authentication/adc-troubleshooting/user-creds. warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING)
난 경고메시지 무시하면 진행이 안 되더라.
알고보니 Client 설정 시 project = ‘
이 칸에 유효한 프로젝트명을 넣어야 한다
’ ✔️ 프로젝트 ID 확인법
# dataset 확인 [x.table_id for x in client.list_tables(dataset)][:5]
# pip install db-dtypes # pip install --upgrade 'google-cloud-bigquery[all]' # pip install --upgrade google-cloud-bigquery-storage google-cloud-bigquery-datatransfer
# table_referencce 생성 table_ref_20160801 = dataset_ref.table('ga_sessions_20160801') table_20160801 = client.get_table(table_ref_20160801) # 데이터 확인 client.list_rows(table_20160801, max_results = 5).to_dataframe()
오류의 연속………………
설치를 해도 해결이 되지 않아서(warning 뜸) VScode 재실행하니까 해결..
totals, trafficSource, device, geoNetwork, customDimensions, hits 컬럼들은 여러 데이터들이 딕셔너리값으로 되어있어서 컬럼별 데이터 타입을 볼 것임
- 함수로 만들고
# 데이터별로 정리 def format_schema_field(schema_field, indent = 0): indent_str = " " * indent field_info = f"{indent_str}{schema_field.name} ({schema_field.field_type})" if schema_field.mode != "NULLABLE": field_info += f" - {schema_field.mode}" if schema_field.description: field_info += f" - {schema_field.description}" nested_indent = indent + 2 if schema_field.field_type == "RECORD": for sub_field in schema_field.fields: field_info += "\n" + format_schema_field(sub_field, nested_indent) return field_info
- 출력한다.
for i in range(5,11): print(format_schema_field(table_20160801.schema[i])) print('\n')
totals
, trafficSource
, device
, geoNetwork
, customDimensions
, hits
결과 확인
totals (RECORD) visits (INTEGER) hits (INTEGER) pageviews (INTEGER) timeOnSite (INTEGER) bounces (INTEGER) transactions (INTEGER) transactionRevenue (INTEGER) newVisits (INTEGER) screenviews (INTEGER) uniqueScreenviews (INTEGER) timeOnScreen (INTEGER) totalTransactionRevenue (INTEGER) sessionQualityDim (INTEGER) trafficSource (RECORD) referralPath (STRING) campaign (STRING) source (STRING) medium (STRING) keyword (STRING) adContent (STRING) adwordsClickInfo (RECORD) campaignId (INTEGER) adGroupId (INTEGER) creativeId (INTEGER) criteriaId (INTEGER) page (INTEGER) slot (STRING) criteriaParameters (STRING) gclId (STRING) customerId (INTEGER) adNetworkType (STRING) targetingCriteria (RECORD) boomUserlistId (INTEGER) isVideoAd (BOOLEAN) isTrueDirect (BOOLEAN) campaignCode (STRING) device (RECORD) browser (STRING) browserVersion (STRING) browserSize (STRING) operatingSystem (STRING) operatingSystemVersion (STRING) isMobile (BOOLEAN) mobileDeviceBranding (STRING) mobileDeviceModel (STRING) mobileInputSelector (STRING) mobileDeviceInfo (STRING) mobileDeviceMarketingName (STRING) flashVersion (STRING) javaEnabled (BOOLEAN) language (STRING) screenColors (STRING) screenResolution (STRING) deviceCategory (STRING) geoNetwork (RECORD) continent (STRING) subContinent (STRING) country (STRING) region (STRING) metro (STRING) city (STRING) cityId (STRING) networkDomain (STRING) latitude (STRING) longitude (STRING) networkLocation (STRING) customDimensions (RECORD) - REPEATED index (INTEGER) value (STRING) hits (RECORD) - REPEATED hitNumber (INTEGER) time (INTEGER) hour (INTEGER) minute (INTEGER) isSecure (BOOLEAN) isInteraction (BOOLEAN) isEntrance (BOOLEAN) isExit (BOOLEAN) referer (STRING) page (RECORD) pagePath (STRING) hostname (STRING) pageTitle (STRING) searchKeyword (STRING) searchCategory (STRING) pagePathLevel1 (STRING) pagePathLevel2 (STRING) pagePathLevel3 (STRING) pagePathLevel4 (STRING) transaction (RECORD) transactionId (STRING) transactionRevenue (INTEGER) transactionTax (INTEGER) transactionShipping (INTEGER) affiliation (STRING) currencyCode (STRING) localTransactionRevenue (INTEGER) localTransactionTax (INTEGER) localTransactionShipping (INTEGER) transactionCoupon (STRING) item (RECORD) transactionId (STRING) productName (STRING) productCategory (STRING) productSku (STRING) itemQuantity (INTEGER) itemRevenue (INTEGER) currencyCode (STRING) localItemRevenue (INTEGER) contentInfo (RECORD) contentDescription (STRING) appInfo (RECORD) name (STRING) version (STRING) id (STRING) installerId (STRING) appInstallerId (STRING) appName (STRING) appVersion (STRING) appId (STRING) screenName (STRING) landingScreenName (STRING) exitScreenName (STRING) screenDepth (STRING) exceptionInfo (RECORD) description (STRING) isFatal (BOOLEAN) exceptions (INTEGER) fatalExceptions (INTEGER) eventInfo (RECORD) eventCategory (STRING) eventAction (STRING) eventLabel (STRING) eventValue (INTEGER) product (RECORD) - REPEATED productSKU (STRING) v2ProductName (STRING) v2ProductCategory (STRING) productVariant (STRING) productBrand (STRING) productRevenue (INTEGER) localProductRevenue (INTEGER) productPrice (INTEGER) localProductPrice (INTEGER) productQuantity (INTEGER) productRefundAmount (INTEGER) localProductRefundAmount (INTEGER) isImpression (BOOLEAN) isClick (BOOLEAN) customDimensions (RECORD) - REPEATED index (INTEGER) value (STRING) customMetrics (RECORD) - REPEATED index (INTEGER) value (INTEGER) productListName (STRING) productListPosition (INTEGER) promotion (RECORD) - REPEATED promoId (STRING) promoName (STRING) promoCreative (STRING) promoPosition (STRING) promotionActionInfo (RECORD) promoIsView (BOOLEAN) promoIsClick (BOOLEAN) refund (RECORD) refundAmount (INTEGER) localRefundAmount (INTEGER) eCommerceAction (RECORD) action_type (STRING) step (INTEGER) option (STRING) experiment (RECORD) - REPEATED experimentId (STRING) experimentVariant (STRING) publisher (RECORD) dfpClicks (INTEGER) dfpImpressions (INTEGER) dfpMatchedQueries (INTEGER) dfpMeasurableImpressions (INTEGER) dfpQueries (INTEGER) dfpRevenueCpm (INTEGER) dfpRevenueCpc (INTEGER) dfpViewableImpressions (INTEGER) dfpPagesViewed (INTEGER) adsenseBackfillDfpClicks (INTEGER) adsenseBackfillDfpImpressions (INTEGER) adsenseBackfillDfpMatchedQueries (INTEGER) adsenseBackfillDfpMeasurableImpressions (INTEGER) adsenseBackfillDfpQueries (INTEGER) adsenseBackfillDfpRevenueCpm (INTEGER) adsenseBackfillDfpRevenueCpc (INTEGER) adsenseBackfillDfpViewableImpressions (INTEGER) adsenseBackfillDfpPagesViewed (INTEGER) adxBackfillDfpClicks (INTEGER) adxBackfillDfpImpressions (INTEGER) adxBackfillDfpMatchedQueries (INTEGER) adxBackfillDfpMeasurableImpressions (INTEGER) adxBackfillDfpQueries (INTEGER) adxBackfillDfpRevenueCpm (INTEGER) adxBackfillDfpRevenueCpc (INTEGER) adxBackfillDfpViewableImpressions (INTEGER) adxBackfillDfpPagesViewed (INTEGER) adxClicks (INTEGER) adxImpressions (INTEGER) adxMatchedQueries (INTEGER) adxMeasurableImpressions (INTEGER) adxQueries (INTEGER) adxRevenue (INTEGER) adxViewableImpressions (INTEGER) adxPagesViewed (INTEGER) adsViewed (INTEGER) adsUnitsViewed (INTEGER) adsUnitsMatched (INTEGER) viewableAdsViewed (INTEGER) measurableAdsViewed (INTEGER) adsPagesViewed (INTEGER) adsClicked (INTEGER) adsRevenue (INTEGER) dfpAdGroup (STRING) dfpAdUnits (STRING) dfpNetworkId (STRING) customVariables (RECORD) - REPEATED index (INTEGER) customVarName (STRING) customVarValue (STRING) customDimensions (RECORD) - REPEATED index (INTEGER) value (STRING) customMetrics (RECORD) - REPEATED index (INTEGER) value (INTEGER) type (STRING) social (RECORD) socialInteractionNetwork (STRING) socialInteractionAction (STRING) socialInteractions (INTEGER) socialInteractionTarget (STRING) socialNetwork (STRING) uniqueSocialInteractions (INTEGER) hasSocialSourceReferral (STRING) socialInteractionNetworkAction (STRING) latencyTracking (RECORD) pageLoadSample (INTEGER) pageLoadTime (INTEGER) pageDownloadTime (INTEGER) redirectionTime (INTEGER) speedMetricsSample (INTEGER) domainLookupTime (INTEGER) serverConnectionTime (INTEGER) serverResponseTime (INTEGER) domLatencyMetricsSample (INTEGER) domInteractiveTime (INTEGER) domContentLoadedTime (INTEGER) userTimingValue (INTEGER) userTimingSample (INTEGER) userTimingVariable (STRING) userTimingCategory (STRING) userTimingLabel (STRING) sourcePropertyInfo (RECORD) sourcePropertyDisplayName (STRING) sourcePropertyTrackingId (STRING) contentGroup (RECORD) contentGroup1 (STRING) contentGroup2 (STRING) contentGroup3 (STRING) contentGroup4 (STRING) contentGroup5 (STRING) previousContentGroup1 (STRING) previousContentGroup2 (STRING) previousContentGroup3 (STRING) previousContentGroup4 (STRING) previousContentGroup5 (STRING) contentGroupUniqueViews1 (INTEGER) contentGroupUniqueViews2 (INTEGER) contentGroupUniqueViews3 (INTEGER) contentGroupUniqueViews4 (INTEGER) contentGroupUniqueViews5 (INTEGER) dataSource (STRING) publisher_infos (RECORD) - REPEATED dfpClicks (INTEGER) dfpImpressions (INTEGER) dfpMatchedQueries (INTEGER) dfpMeasurableImpressions (INTEGER) dfpQueries (INTEGER) dfpRevenueCpm (INTEGER) dfpRevenueCpc (INTEGER) dfpViewableImpressions (INTEGER) dfpPagesViewed (INTEGER) adsenseBackfillDfpClicks (INTEGER) adsenseBackfillDfpImpressions (INTEGER) adsenseBackfillDfpMatchedQueries (INTEGER) adsenseBackfillDfpMeasurableImpressions (INTEGER) adsenseBackfillDfpQueries (INTEGER) adsenseBackfillDfpRevenueCpm (INTEGER) adsenseBackfillDfpRevenueCpc (INTEGER) adsenseBackfillDfpViewableImpressions (INTEGER) adsenseBackfillDfpPagesViewed (INTEGER) adxBackfillDfpClicks (INTEGER) adxBackfillDfpImpressions (INTEGER) adxBackfillDfpMatchedQueries (INTEGER) adxBackfillDfpMeasurableImpressions (INTEGER) adxBackfillDfpQueries (INTEGER) adxBackfillDfpRevenueCpm (INTEGER) adxBackfillDfpRevenueCpc (INTEGER) adxBackfillDfpViewableImpressions (INTEGER) adxBackfillDfpPagesViewed (INTEGER) adxClicks (INTEGER) adxImpressions (INTEGER) adxMatchedQueries (INTEGER) adxMeasurableImpressions (INTEGER) adxQueries (INTEGER) adxRevenue (INTEGER) adxViewableImpressions (INTEGER) adxPagesViewed (INTEGER) adsViewed (INTEGER) adsUnitsViewed (INTEGER) adsUnitsMatched (INTEGER) viewableAdsViewed (INTEGER) measurableAdsViewed (INTEGER) adsPagesViewed (INTEGER) adsClicked (INTEGER) adsRevenue (INTEGER) dfpAdGroup (STRING) dfpAdUnits (STRING) dfpNetworkId (STRING)
2. Make Our Goals Concrete
1. 가장 인기 있는 페이지와 이탈률 분석
2. 브라우저 및 디바이스별 세션 수 탐색
3. 사이트 트래픽 유형과 품질 탐색
4. 고객 전환 경로 및 잠재적인 병목 현상 파악
5. 베스트셀러 제품 카테고리 식별 및 수요 예측
3. Explore and Analyze Data
1. Most Popular Pages
1-1 bounce rate
- 자주 방문하는 페이지와 해당 페이지의 이탈률 확인
이탈률 = 이탈 횟수 / 총 세션 수
- 여기서 이탈 횟수((사용자가 사이트에 들어왔다가 바로 떠난 세션))
- 이탈률이 높을 때의 추측
- 사용자가 사이트에서 기대한 내용을 못 봤을 때 - 검색 엔진 최적화(SEO) 수행 필요
- 페이지에 기능 또는 디스플레이 문제가 있을 때
# hit = 1 query = """ SELECT hits.page.pagePath AS landing_page, COUNT(*) AS views, SUM(totals.bounces)/COUNT(*) AS bounce_rate FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' AND hits.type = 'PAGE' AND hits.hitNumber = 1 GROUP BY landing_page ORDER BY views DESC LIMIT 10 """ result = client.query(query).result().to_dataframe() result.head(10)
# Google Cloud SDK Shell gcloud auth login
계속 삽질하다가 깨달았음… 프로젝트명 설정할 때 오류가 났던 이유는 이거였다.
다시 실행을 해 봤는데 또 오류 !
BadRequest: 400 Syntax error: Unclosed string literal at [10:50]
Location: US
..그냥 ‘ 하나 안 써줘서 오류난 거였다.. → 오타..
BadRequest: 400 Syntax error: Unexpected string literal 'bigquery-public-data.google_analytics_sample.ga_...' at [7:13]
Location: US
만약 이런 오류가 났다면
bigquery-public-data.google_analytics_sample.ga_sessions_*
이 부분에서 작은 따옴표가 아닌 ````` 물결~과 같이 있는 ` 요거다.
빅쿼리 FROM으로 불러올 때는 ``을 쓰더라.
웹사이트에서 사용자가 처음 페이지를 방문한 순간의 정보
- FROM
- 샘플 데이터셋에서 ga_sessions_*이 파티션화된 테이블
UNNEST(hits) AS hits
중첩된 hits필드 펼치기 (반복 레코드 필드임)
- WHERE
_TABLE_SUFFIX
를 기반으로 20160801 ~ 20170801 데이터 필터링,hits.type
Page형식의 히트만 고려hits.hitNumber
hit 1만 표시 즉, 사용자가 처음 페이지를 방문한 순간
- GROUP BY
landing_page
필드를 기반으로 데이터 그룹화
- SELECT
- 해당되는 데이터의
landing_page
,views
,bounce_rate
만 볼 것임(AS
로 컬럼명 수정) landing_page
페이지 경로(path)views
카운트 COUNT(*)bounce_rate
이탈률 = 이탈한 방문 수(totals.bounces의 합) / 총 방문 수(총 count)
- ORDER BY
- views를 기준으로 내림차순 정렬
- LIMIT 10
- 파이썬에서 df.head(10)과 비슷한 기능. 10개만 제한해서 보여준다.
Men's
Apparel
과 Bags
다른 페이지에 비해 이탈률(bounce_rate)이 상대적으로 낮다.youtube
, drinkware
조회수(views)는 많지만 이탈률(bounce_rate)이 높다. 2-2 exit rate
- exit rate는 랜딩 페이지뿐만 아니라 모든 페이지에 대해 계산
이탈률(exit_rate) = 이탈 수 / 총 세션 수
- (이탈 수 = 사용자가 페이지로 이동한 후 사이트를 떠난 세션)
- exit_rate이 높으면 사용자가 페이지로 이동할 때 예상한 내용이 표시되지 않거나 페이지 기능 또는 디스플레이에 문제가 있는 것
query = """ SELECT hits.page.pagePath AS page, COUNT(*) AS views, SUM(totals.bounces)/COUNT(*) AS exit_rate FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' AND hits.type = 'PAGE' GROUP BY page ORDER BY views DESC LIMIT 10 """ result = client.query(query).result().to_dataframe() result.head(10)
다른 페이지에 비해 남성 의류 관련 페이지의 exit_rate이 약간 높음
youtube의 exit_rate이 매우 높음
1-3 bounce_rate와 exit_rate의 차이
query = """ SELECT hits.page.pagePath AS landing_page, COUNT(*) AS views, SUM(totals.bounces)/COUNT(*) AS bounce_rate FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' AND hits.type = 'PAGE' AND hits.hitNumber = 1 GROUP BY landing_page ORDER BY views DESC LIMIT 10 """ result = client.query(query).result().to_dataframe() result.head(10)
query = """ SELECT hits.page.pagePath AS page, COUNT(*) AS views, SUM(totals.bounces)/COUNT(*) AS exit_rate FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' AND hits.type = 'PAGE' GROUP BY page ORDER BY views DESC LIMIT 10 """ result = client.query(query).result().to_dataframe() result.head(10)
2. Browser and Device
브라우저와 디바이스별로 세션과 호환성 문제 확인
query = """ SELECT device.Browser AS browser, COUNT(*) AS sessions, SUM(totals.bounces)/COUNT(*) AS exit_rate FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' GROUP BY browser ORDER BY sessions DESC LIMIT 10 """ result = client.query(query).result().to_dataframe() result.head(10)
상위 5개 브라우저 중
Chrome
의 이탈률은 9%로 비교적 낮은 반면,
이탈률이 19%인
Internet Explorer
를 제외한 나머지 브라우저는 Chrome
에 비해 약 7~8% 정도 높음3. Traffic Type and Quality
사이트로 유입되는 각 Traffic Type에 대한 세션 및 트랜잭션 데이터
query = """ SELECT trafficSource.medium AS medium, COUNT(*) AS sessions, SUM(totals.bounces)/COUNT(*) AS exit_rate, SUM(totals.transactions) AS transactions, SUM(totals.totalTransactionRevenue)/1000000 AS total_revenue, SUM(totals.transactions)/COUNT(*) AS conversion_rate FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' GROUP BY medium ORDER BY sessions DESC """ result = client.query(query).result().to_dataframe() result.head(10)
traffic(medium)은 대부분
organic
, referral
인 것을 확인cpc
와 cpm
의 전환율(conversion_rate)이 다른 소스에 비해 상당히 높음전환율(conversion_rate) = 트랜잭션이 완료된 세션의 비율
4. Identify Conversion Path and Possible Bottlenecks
고객의 전환 경로와 전환 과정에서 사용자가 사이트를 이탈하는 영역 식별
# action type별 총 조회수(hits) 집계 query = """ SELECT CASE WHEN hits.eCommerceAction.action_type = '1' THEN 'Click through of product lists' WHEN hits.eCommerceAction.action_type = '2' THEN 'Product detail views' WHEN hits.eCommerceAction.action_type = '5' THEN 'Check out' WHEN hits.eCommerceAction.action_type = '6' THEN 'Completed purchase' END AS action, COUNT(fullvisitorID) AS users, FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits, UNNEST(hits.product) AS product WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' AND ( hits.eCommerceAction.action_type != '0' AND hits.eCommerceAction.action_type != '3' AND hits.eCommerceAction.action_type != '4' ) GROUP BY action ORDER BY users DESC """ result = client.query(query).result().to_dataframe() result.head(10)
- FROM
ga_sessions_*
지정된 날짜 범위 내의 모든 테이블을 쿼리UNNEST
함수를 사용하여hits
및hits.product
필드를 펼치기 → 중첩된 데이터 사용
- WHERE
_TABLE_SUFFIX
를 사용하여 날짜 범위 지정(20160801 ~ 20170801)hits.eCommerceAction.action_type
필드가 '0', '3', '4'가 아닌 행만 선택
- GROUP BY
action
열을 기반으로 데이터 그룹화
- SELECT
- action type에 따른 행동 유형 명칭 지정
action_type = 1
제품 목록 클릭action_type = 2
제품 세부 정보 보기action_type = 5
결제 단계action_type = 6
구매 완료
- ORDER BY
- users 사용자 수를 기준으로 내림차순
Create Funnel Graph
# funnel graph import plotly.graph_objs as go funnel_graph = go.Figure(go.Funnel(y = result['action'], x = result['users'], textposition = 'inside', # Funnel 그래프 안에 텍스트를 표시할 위치를 'inside'로 설정 textinfo = 'value + percent initial'), # 각 단계의 값과 초기값의 백분율을 나타내도록 설정 layout = go.Layout(height = 400, width = 800) ) funnel_graph.update_layout(title_text = 'Google Merchandise Store Conversion Path') funnel_graph.show()
textinfo
매개변수는 Funnel 그래프의 각 단계에서 텍스트 정보를 어떻게 표시할지를 지정하는 부분입니다. textinfo
값을 'value+percent initial'
로 설정한 경우, 그래프의 각 단계에 대한 텍스트 정보가 다음과 같이 표시됩니다:'value'
: 현재 단계의 값, 즉 해당 단계에서의 사용자 수가 표시됩니다.
'percent initial'
: 해당 단계의 값이 초기 단계 값에 대한 백분율로 표시됩니다.
예를 들어, Funnel 그래프의 첫 번째 단계가 'Visitors'이고 해당 값이 1000이라면, 텍스트로는 "1000 (100% initial)"와 같이 표시됩니다. 이것은 해당 단계의 사용자 수가 초기 단계에서 100%를 나타내는 것을 의미합니다.
이렇게 설정된
textinfo
는 그래프의 각 단계에 대한 정보를 더 상세하게 표시하여 사용자가 그래프를 이해하는 데 도움을 줍니다.제품 세부 정보를 확인한 사용자의
69%
가 결제 페이지로 이동
그러나 이러한 사용자 중 실제로 구매를 완료한 비율은 30%
에 불과하다는 것을 알 수 있음5. Identify Best-Selling Product Categories and Forecast Demand
가장 인기 있는 제품 카테고리
query = """ SELECT product.v2ProductCategory AS category, SUM(totals.transactions) AS transactions, SUM(totals.totalTransactionRevenue)/1000000 AS total_revenue FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits, UNNEST(hits.product) AS product WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' GROUP BY category ORDER BY total_revenue DESC LIMIT 10 """ cat_result = client.query(query).result().to_dataframe() cat_result.head(10)
가장 많이 팔리는 카테고리 중 일부는
Apparel
와 관련이 있으며, Men's-T-Shirts
가 가장 높은 순위Office
, Electronics
, Water Bottles and Tumblers
도 잘 팔리고 있음Apparel
카테고리에서 가장 잘 팔리는 제품인 Men's T-Shirts
의 수요를 예측하기 위해 7일간의 거래 이동 평균을 계산query = """ WITH daily_mens_tshirt_transactions AS ( SELECT date, SUM(totals.transactions) AS transactions FROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`, UNNEST(hits) AS hits, UNNEST(hits.product) AS product WHERE _TABLE_SUFFIX BETWEEN '20160801' AND '20170801' AND product.v2ProductCategory = "Home/Apparel/Men's/Men's-T-Shirts/" GROUP BY date ORDER BY date ) SELECT date, AVG(transactions) OVER( ORDER BY date ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING ) AS avg_transactions FROM daily_mens_tshirt_transactions """ result = client.query(query).result().to_dataframe() result['date'] = pd.to_datetime(result['date']) result.plot(y = 'avg_transactions', x = 'date', kind = 'line', title = 'Men\'s T-Shirts Conversions 7-Day Moving Average', figsize = (12, 6)) plt.show()
Men's T-shirts의 수요에 계절적 요인이 있는 것으로 추정됨
Office, Water Bottles and Tumblers의 이동 평균도 살펴보고 비슷한 추세가 있는지 확인
Share article