| 항목 | SGD | ALS |
|---|---|---|
| 방식 | 경사하강법. 사용자-아이템 한 쌍씩 점진적 업데이트 (샘플 단위) | 교대로 선형 방정식(Least Square) 풀기 (블록 단위) |
| 속도 | 느리지만 유연하고 확장성 좋음 | 반복 횟수 적어도 빠르게 수렴 |
| 병렬화 | 어려움 (업데이트 간 의존성 큼) | 병렬 처리 가능, 분산환경에 최적화 |
| 용도 | 소규모 데이터, 커스터마이징, 온라인 학습 | 대규모 추천 시스템 (Netflix, Spark 등) |
| 장점 | 다양한 커스터마이징, 세밀한 업데이트 | 대용량 처리 가능, 빠른 속도, 정규화 용이 |
| 단점 | 느리고 병렬화 어려움 | 소규모 데이터에는 비효율적 |
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("ALS Recommendation Example").master('local[*]').getOrCreate()
print("Spark Session이 생성되었습니다.")
출력
Spark Session이 생성되었습니다.
from pyspark.sql import Row
ratings = [
Row(userId=0, itemId=0, rating=4.0),
Row(userId=0, itemId=1, rating=2.0),
Row(userId=1, itemId=1, rating=3.0),
Row(userId=1, itemId=2, rating=4.0),
Row(userId=2, itemId=2, rating=5.0),
Row(userId=2, itemId=0, rating=1.0),
]
df = spark.createDataFrame(ratings)
df.show()
출력
+------+------+------+
|userId|itemId|rating|
+------+------+------+
| 0| 0| 4.0|
| 0| 1| 2.0|
| 1| 1| 3.0|
| 1| 2| 4.0|
| 2| 2| 5.0|
| 2| 0| 1.0|
+------+------+------+
설명:
from pyspark.ml.recommendation import ALS
(training, test) = df.randomSplit([0.8, 0.2], seed=42)
als = ALS(
maxIter=10, # 반복 학습 횟수
regParam=0.1, # 정규화 파라미터
rank=2, # 잠재요인 수
userCol="userId",
itemCol="itemId",
ratingCol="rating",
)
model = als.fit(training)
print("ALS 모델이 학습되었습니다.")
출력
ALS 모델이 학습되었습니다.
predictions = model.transform(test)
predictions.show()
from pyspark.ml.evaluation import RegressionEvaluator
evaluator = RegressionEvaluator(
metricName="rmse",
labelCol="rating",
predictionCol="prediction"
)
rmse = evaluator.evaluate(predictions)
print(f"테스트 RMSE : {rmse:.4f}")
출력
+------+------+------+----------+
|userId|itemId|rating|prediction|
+------+------+------+----------+
| 1| 1| 3.0| NaN |
| 1| 2| 4.0| NaN |
+------+------+------+----------+
테스트 RMSE : 0.8777
설명:
!wget http://files.grouplens.org/datasets/movielens/ml-latest-small.zip
!unzip -o ml-latest-small.zip
ratings = spark.read.csv("ml-latest-small/ratings.csv", header=True, inferSchema=True)
movies = spark.read.csv("ml-latest-small/movies.csv", header=True, inferSchema=True)
ratings = ratings.select("userId", "movieId", "rating")
(train, test) = ratings.randomSplit([0.8, 0.2], seed=42)
als = ALS(
userCol="userId",
itemCol="movieId",
ratingCol="rating",
rank=10,
maxIter=10,
regParam=0.1,
coldStartStrategy="drop"
)
model = als.fit(train)
print("ALS 모델 학습 완료")
출력
ALS 모델 학습 완료
predictions = model.transform(test)
evaluator = RegressionEvaluator(
metricName="rmse",
labelCol="rating",
predictionCol="prediction"
)
rmse = evaluator.evaluate(predictions)
print(f"테스트 RMSE : {rmse:.4f}")
userRecs = model.recommendForAllUsers(5)
userRecs.show(5, truncate=False)
출력
테스트 RMSE : 0.8777
+------+-------------------------------------------------------------------+
|userId|recommendations |
+------+-------------------------------------------------------------------+
|1 |[{96004, 5.72}, {81562, 5.71}, {92758, 5.68}, {72887, 5.67}, ...] |
|2 |[{84847, 4.90}, {91658, 4.82}, {94193, 4.79}, {69481, 4.75}, ...] |
|3 |[{3837, 5.00}, {81834, 4.98}, {66028, 4.92}, {53149, 4.89}, ...] |
|4 |[{25825, 5.37}, {81562, 5.34}, {91842, 5.28}, {89492, 5.26}, ...] |
|5 |[{7008, 4.88}, {53883, 4.86}, {90754, 4.83}, {91842, 4.80}, ...] |
+------+-------------------------------------------------------------------+
from pyspark.sql.functions import explode
recs = userRecs.withColumn("rec", explode("recommendations")) \
.select("userId", "rec.movieId", "rec.rating") \
.withColumnRenamed("rec.movieId", "movieId") \
.withColumnRenamed("rec.rating", "rating")
final_recs = recs.join(movies, on="movieId")
final_recs.select("userId", "title", "rating").show(10, truncate=False)
출력 예시
+------+------------------------------------------------------+---------+
|userId|title |rating |
+------+------------------------------------------------------+---------+
|1 |Dragon Ball Z: The History of Trunks (1993) |5.7296 |
|1 |On the Beach (1959) |5.7296 |
|1 |Stranger Than Paradise (1984) |5.7151 |
|1 |Three Billboards Outside Ebbing, Missouri (2017) |5.6840 |
|1 |Victory (1981) |5.6726 |
|2 |Emma (2009) |4.9079 |
|2 |The Jinx: The Life and Deaths of Robert Durst (2015) |4.9029 |
|2 |Wet Hot American Summer (2001) |4.8267 |
|2 |Dune (2000) |4.7336 |
|2 |Saving Face (2004) |4.7290 |
+------+------------------------------------------------------+---------+
| 항목 | 내용 |
|---|---|
| 목적 | 대규모 추천 시스템에서 사용자-아이템 평점 예측 및 추천 생성 |
| 잠재요인 기반 이유 | 숨겨진 사용자/아이템 패턴을 학습해 추천에 활용 |
| 사용 분야 | 넷플릭스, 아마존, 스포티파이, 쿠팡 등 대형 플랫폼 추천 시스템 |
| PySpark ALS 이유 | 분산 처리, 병렬 연산 최적화, 대규모 데이터에 적합 |
| SGD와 차이점 | SGD는 소규모·커스터마이징에 강점 / ALS는 대규모·병렬 연산에 강점 |
| 한계점 | 소규모 데이터에는 비효율, 파라미터 민감, 해석 어려움 |