완전한 비교 표 만들기

빅 데이터Beginner
지금 연습하기

소개

쇼핑몰은 이제 조회된 세션/상품 쌍과 반복 이벤트를 구분할 수 있습니다. 다음 질문은 어느 상품에서 유효한 추가가 없는 조회 세션의 비중이 높고, 각 비교를 뒷받침하는 관찰량은 얼마인가입니다.

조회 세션 분모, 완료 수, 미완료 수와 비율이 있는 완전한 표를 만듭니다. 유효한 추가가 0인 상품과 모든 동률을 유지하세요. 결과는 추가 조사에 쓸 관찰 단서이며, 상품이나 페이지가 방문을 멈추게 했다는 증명은 아닙니다.

이 독립 실습은 앞선 가이드 실습에서 완성한 여정 모듈과 새 원시 파일을 제공합니다. 그 실습의 최초 조회, 세션/상품, 시간 규칙과 Spark 그룹화 및 Parquet을 알아야 합니다. Terminal을 사용하세요. 배치는 유한하고 종료되어 있으며 식별자와 초 단위 UTC 시각이 유효하고, 반복 이벤트 ID는 정확한 복사본입니다. 저자 예상은 35~45분입니다. 스트리밍, 고유 인원 추정, 인과 추론은 다루지 않습니다.

완전한 상품 비교 만들기

조회 여정마다 한 행인 데이터를 상품마다 한 행으로 집계합니다. Terminal에서 시작하세요. 제공 프로그램 중 analysis.py만 수정하세요. 원시 파일과 run_analysis.py, read_result.py, support.py를 그대로 유지하고 파생 결과는 output/에 두세요.

cd /home/labex/project
cat data/batch.csv
cat analysis.py

이 모듈에는 이전 실습에서 독립적으로 준비한 read_events, build_views, build_journeys가 있습니다. 모듈은 재사용 함수를 담습니다. 드라이버는 현재 SparkSession과 입력 경로를 전달하고, 반환된 여정 DataFrame을 새 build_report(journeys)에 넘깁니다. 이전 VM이나 터미널 세션의 아무것도 필요 없습니다.

계약을 떠올리세요. 완전히 같은 이벤트 복사본은 제거하고, 조회된 각 (session_id, product_id)는 최초 조회를 사용합니다. 유효한 추가는 두 키가 같고 그 조회와 같은 시각 또는 이후여야 합니다. 여러 유효 추가도 완료 여정 하나입니다. 드라이버는 local[2], UTC 형식, 드라이버와 워커에 같은 Python을 사용하며 함수가 반환된 뒤 출력합니다.

조회 쌍 셋, 완료 쌍 둘인 상품을 손으로 계산하세요. 조회 세션 셋, 장바구니 세션 둘, 장바구니 없는 세션 하나, 장바구니 없는 비율 1/3입니다. 분모 없는 비율은 한 방문을 큰 표본만큼 설득력 있어 보이게 할 수 있습니다.

count("*")는 이제 원시 이벤트가 아니라 여정 행을 셉니다. Boolean completed를 long으로 변환하면 true는 1, false는 0입니다. Spark의 sum이 값을 더합니다. 완료 수를 빼면 미완료 수이며 양수인 조회 세션 수로 나누면 0~1 비율입니다. 여기서는 모든 그룹에 조회가 하나 이상 있습니다. 추가만 있는 상품은 그룹이나 분모가 없으며, 0 분모 비율을 만들어 내지 않습니다.

상품 집계만 작성하기

제공된 read_events, build_views, build_journeys는 유지하세요. 앞선 실습에서 완성한 내용이므로 다시 입력하지 마세요. F는 기존 Spark 함수 별칭입니다. nano로 같은 모듈을 여세요.

nano analysis.py

방향키로 build_journeys의 끝에 가서 빈 줄을 두세요. 연습했듯 Ctrl+W로 함수 이름을 검색할 수 있습니다. 새 선언은 각각 왼쪽 끝에서 시작하고 본문은 공백 네 개를 사용합니다. 준비된 정답 틀을 채우는 것이 아니라 build_report 전체를 작성합니다.

먼저 여정 DataFrame을 상품별로 그룹화하세요. 같은 집계 안에서 개수 두 개를 구합니다. 모든 행을 세어 조회 분모를 구하고, Boolean 완료 값을 정수로 변환하여 합합니다. 드라이버가 사용하는 필드 이름을 유지하세요.

def build_report(journeys):
    counts = journeys.groupBy("product_id").agg(
        F.count("*").alias("view_sessions"),
        F.sum(F.col("completed").cast("long")).alias("cart_sessions"),
    )

함수 안에서 계속하세요. withColumn은 그룹별 개수로부터 이름이 있는 열을 만듭니다. 조회 수에서 완료 수를 뺀 뒤 같은 양수 조회 분모로 나누세요. 먼저 완료 행만 필터링하지 마세요. 그러면 유효한 추가가 없는 상품이 사라집니다. 최댓값 하나만 선택하지 마세요. 동률 상품은 모두 보고서에 속합니다.

    return counts.withColumn(
        "no_cart_sessions", F.col("view_sessions") - F.col("cart_sessions")
    ).withColumn(
        "no_cart_ratio", F.col("no_cart_sessions") / F.col("view_sessions")
    )

Ctrl+O로 저장하고 Enter로 analysis.py를 확인한 뒤 Ctrl+X로 종료하세요. 다시 열어 저장된 함수를 살펴보고 앞선 함수들이 남아 있는지 확인하세요.

nano analysis.py

Ctrl+W로 build_report를 찾으세요. 실수가 있다면 방향키와 Backspace/Delete로 해당 줄만 바꾸고 두 번째 정의를 추가하지 마세요. 이어지는 줄의 들여쓰기와 닫는 괄호를 유지하세요. 변경 내용을 저장하고 종료한 뒤 파일을 읽으세요.

cat analysis.py

다음 실행에서 SyntaxError나 IndentationError가 나면 nano에서 지정된 줄을 찾고 주변 함수, 괄호, 공백 네 개의 들여쓰기를 확인한 뒤 저장하고 다시 실행하세요. 계산은 성공했지만 개수나 비율이 잘못되었다면 그룹화, 형 변환, 분모를 확인해야 합니다. 보고서를 고치려고 VM을 초기화하거나 동작하는 G1 함수들을 다시 쓰지 마세요.

입력과 출력 경로를 명시해 보고서 단계를 실행하세요.

bigdata-python run_analysis.py data/batch.csv output/main --stage report

다음 완전한 논리 표를 기대하세요. 부동소수점 표시는 더 많은 자릿수를 가질 수 있습니다.

product_id  view_sessions  cart_sessions  no_cart_sessions  no_cart_ratio
card        1              0              1                 1.0
pin         1              0              1                 1.0
tea         3              1              2                 0.6666666666666666
book        2              1              1                 0.5
mug         3              2              1                 0.3333333333333333

드라이버는 실제 저장 Parquet을 읽은 뒤 표시합니다. 표는 no_cart_ratio 내림차순, 다음으로 상품 식별자 순입니다. 동률을 읽기 쉽게 하기 위한 것입니다. card와 pin을 모두 남겨야 하며, 정렬 동률은 하나를 버려도 된다는 뜻이 아닙니다. 추가만 있는 poster는 조회 쌍이 없어 제외됩니다.

결과는 output/main/journeys와 output/main/report의 유형이 있는 데이터셋입니다. 후자는 문자열 상품 ID, 정수 개수, 숫자 비율을 가집니다. Parquet 파트 이름과 개수는 구현 세부이며 보고서의 정체성이 아닙니다. 동등한 Spark DataFrame/SQL 표현식을 허용합니다. 제공 입력부터 파이프라인을 유지하고 변환은 Spark 안에서 수행하세요. 원시 여정을 Python에 수집하거나 RDD/pandas로 바꾸거나 체크포인트 후 재생성하지 마세요.

파일을 읽고 스냅샷 다시 만들기

작은 CSV를 읽고 원본을 바꾸지 않은 채 파생 스냅샷을 대체합니다. Terminal의 /home/labex/project에서 계속하세요.

준비된 드라이버는 동료를 위해 output/main/report.csv를 단일 소형 UTF-8 CSV로 저장합니다. build_report 반환 후 이미 집계된 최종 상품 표만 직렬화를 위해 수집합니다. 이 마지막 표현 과정이 Spark 변환을 대체하지는 않습니다. 실제 파일을 보세요.

cat output/main/report.csv

헤더는 Parquet 보고서와 같은 다섯 필드입니다. 다섯 상품 모두, card와 pin의 장바구니 세션 수 0, 두 동률 비율 1.0을 확인하세요. CSV는 행과 필드로 읽을 수 있지만 줄 수나 파일명만으로 관계를 증명할 수 없습니다.

제공 리더로 실제 Parquet 두 데이터셋과 CSV를 읽으세요. read_result.py는 주어진 출력 경로를 읽고 Spark 안에서 시각을 UTC로 형식화하며 CSV 내용과 저장 표를 비교합니다. 없는 결과를 만들거나 채우지 않습니다.

bigdata-python read_result.py output/main

여정 열 행, 상품 다섯 행과 CSV matches stored report를 기대하세요. 파일이 없으면 올바른 입력과 목적지로 분석을 다시 실행합니다. 리더는 답을 꾸며 내지 않고 의도적으로 실패합니다.

sha256sum은 각 원시 파일의 내용 지문을 출력합니다. *.csv 패턴은 data/의 CSV를 고릅니다. 재구축 전후의 행을 비교하세요.

sha256sum data/*.csv
bigdata-python run_analysis.py data/batch.csv output/main --stage report
bigdata-python read_result.py output/main
sha256sum data/*.csv

같은 입력은 상품이나 여정 중복 없이 같은 논리 표를 만듭니다. 원시 지문은 변하지 않아야 합니다. Parquet의 새 파일명이나 바이트는 재구축마다 달라질 수 있습니다. 반복 가능성 계약은 논리 내용입니다. 작성기는 이 알려진 파생 목적지만 대체하며 원시 파일이나 다른 결과 디렉터리는 바꾸지 않습니다.

이제 저장 모듈을 일반 샘플과 별도 목적지에 사용하세요.

bigdata-python run_analysis.py data/normal.csv output/normal --stage report
bigdata-python read_result.py output/normal

상품 두 행이 각각 조회 세션 1, 장바구니 세션 1, 장바구니 없는 세션 0, 비율 0이어야 합니다. 주 결과는 유지됩니다. 같은 매개변수화된 함수가 두 배치를 모두 처리합니다.

이 작은 배치의 card와 pin은 주목할 만하지만 관찰 세션이 각각 하나뿐입니다. 높은 비율이 방문 중단 이유나 고유 인원을 밝히거나 패턴의 지속을 보장하지는 않습니다. 개수와 모든 동률이 있어 관찰을 검토할 수 있으며 인과 주장에는 추가 증거가 필요합니다.

채점은 실제 결과를 다시 만들지 않고 읽습니다. 또 미변경 모듈을 불러 다른 식별자와 행 순서의 일회용 배치에서 함수를 호출하고 실제 Spark 입력 계보와 일회용 출력을 읽습니다. 정확한 명령 철자, 직접 쓴 실행 계획, 애플리케이션 이름 표식을 채점하지 않으며 실제 결과를 고치지 않습니다. 함수에서는 쓰지 말고 직렬화는 드라이버에 맡기세요.

요약

완전한 Parquet/CSV 비교를 만들고 읽고, 추가 0인 상품과 동률을 유지하고, 원시 입력을 보존하며 파생 스냅샷을 다시 만들었습니다. 분모와 개수 열이 각 비율을 설명합니다. 종료 세션의 패턴은 추가 관찰을 뒷받침하며 인과 주장이 아닙니다.