๐๏ธ ํ์ต์ผ: 2026.06
๐ ์ถ์ฒ: Databricks ์์ ์๋ฃ (5_Aggregation.ipynb)
"๋ฐ์ดํฐ๋ฅผ ๊ทธ๋ฃน์ผ๋ก ๋ฌถ๊ณ (groupBy), ๊ทธ ๊ทธ๋ฃน์ ์ง๊ณ๋ฅผ ์ ์ฉํ๋ค(agg / count / sum / avg โฆ)"
์ง๊ณ๋ ์ฌ๋ฌ ํ(row)์ ํ๋์ ์์ฝ ๊ฐ์ผ๋ก ์์ถํ๋ ์์ ์ด๋ค.
๋น์ ๐งพ
์์
์์ ํผ๋ฒ ํ
์ด๋ธ์ ๋ง๋ค ๋๋ฅผ ๋ ์ฌ๋ ค๋ณด์.
"์ง์ญ๋ณ ๋งค์ถ ํฉ๊ณ"๋ฅผ ๊ตฌํ ๋, ์๋ฐฑ ๊ฐ์ ํ์ ์ง์ญ์ผ๋ก ๋ฌถ๊ณ , ๋งค์ถ์ ๋ํ์ง ์๋?
PySpark์ groupBy + ์ง๊ณ ํจ์๊ฐ ๋ฐ๋ก ๊ทธ ์ญํ ์ด๋ค.
DataFrame
โโ .groupBy("์ด์ด๋ฆ") โ ๊ทธ๋ฃนํ (GroupedData ๊ฐ์ฒด ์์ฑ)
โโ .count() โ ์ง๊ณ ์ ์ฉ
โโ .avg("๋ค๋ฅธ์ด")
โโ .sum("๋ค๋ฅธ์ด")
โโ .agg(ํจ์1, ํจ์2) โ ์ฌ๋ฌ ์ง๊ณ๋ฅผ ํ ๋ฒ์
groupBy๋ DataFrame์ ํน์ ์ด ๊ธฐ์ค์ผ๋ก ๋ฌถ์ด GroupedData ๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค.
์ด ์์ ์์๋ ์์ง ๊ณ์ฐ์ด ์ผ์ด๋์ง ์๋๋ค. ์ง๊ณ ๋ฉ์๋๋ฅผ ๋ถ์ฌ์ผ ์ค์ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
# ๋จ์ผ ์ด ๊ธฐ์ค
df.groupBy("event_name")
# ์ฌ๋ฌ ์ด ๊ธฐ์ค (์กฐํฉ)
df.groupBy("geo.state", "geo.city")
๐ก ์ค์ฒฉ ์ด(nested column) ์ ๊ทผ
"geo.state"์ฒ๋ผ ์ (.)์ผ๋ก ๊ตฌ๋ถํด์ ์ค์ฒฉ๋ ๊ตฌ์กฐ์ ํ๋์ ์ ๊ทผํ ์ ์๋ค.
| ๋ฉ์๋ | ์ค๋ช |
|---|---|
count() | ๊ฐ ๊ทธ๋ฃน์ ํ ์ |
avg("์ด") | ๊ฐ ๊ทธ๋ฃน์ ํ๊ท |
sum("์ด") | ๊ฐ ๊ทธ๋ฃน์ ํฉ๊ณ |
max("์ด") | ๊ฐ ๊ทธ๋ฃน์ ์ต๋๊ฐ |
min("์ด") | ๊ฐ ๊ทธ๋ฃน์ ์ต์๊ฐ |
agg(...) | ์ฌ๋ฌ ์ง๊ณ๋ฅผ ํ ๋ฒ์ ์ ์ฉ |
# ์ด๋ฒคํธ ์ด๋ฆ๋ณ ํ ์
event_counts_df = df.groupBy("event_name").count()
display(event_counts_df)
# ์ฃผ(state)๋ณ ํ๊ท ๊ตฌ๋งค ์์ต
avg_state_purchases_df = df.groupBy("geo.state").avg("ecommerce.purchase_revenue_in_usd")
display(avg_state_purchases_df)
# ์ฃผ + ๋์ ์กฐํฉ๋ณ ์ด ์๋ & ์์ต ํฉ๊ณ
city_purchase_quantities_df = df.groupBy("geo.state", "geo.city").sum(
"ecommerce.total_item_quantity",
"ecommerce.purchase_revenue_in_usd"
)
display(city_purchase_quantities_df)
pyspark.sql.functions ๋ชจ๋์๋ ๋ ๋ค์ํ ์ง๊ณ ํจ์๊ฐ ์๋ค.
์ด ํจ์๋ค์ agg()์ ํจ๊ป ์ฌ์ฉํ๋ฉฐ, ๊ฒฐ๊ณผ ์ด์ ๋ณ์นญ(alias) ๋ ๋ถ์ผ ์ ์๋ค.
| ํจ์ | ์ค๋ช |
|---|---|
sum("์ด") | ํฉ๊ณ |
avg("์ด") | ํ๊ท |
approx_count_distinct("์ด") | ๊ณ ์ ๊ฐ ๊ฐ์ (๊ทผ์ฌ์น, ๋น ๋ฆ) |
collect_list("์ด") | ๊ทธ๋ฃน ๋ด ๊ฐ์ ๋ฆฌ์คํธ๋ก ๋ฌถ๊ธฐ |
stddev_samp("์ด") | ํ๋ณธ ํ์คํธ์ฐจ |
โ approx_count_distinct vs count(distinct โฆ)
์ ํํ ๊ณ ์ ๊ฐ ์๋ฅผ ์ธ๋ ค๋ฉด ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋ค ๋ด์ผ ํด์ ๋๋ฆฌ๋ค.
approx_count_distinct๋ HyperLogLog ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋น ๋ฅด๊ฒ ๊ทผ์ฌ์น๋ฅผ ๊ตฌํ๋ค.
๋์ฉ๋ ๋ฐ์ดํฐ์์๋ ์ด ํจ์๊ฐ ํจ์ฌ ์ค์ฉ์ ์ด๋ค.
from pyspark.sql.functions import sum
# ๋จ์ผ ์ง๊ณ + alias
state_purchases_df = df.groupBy("geo.state").agg(
sum("ecommerce.total_item_quantity").alias("total_purchases")
)
display(state_purchases_df)
from pyspark.sql.functions import avg, approx_count_distinct
# ์ฌ๋ฌ ์ง๊ณ๋ฅผ ํ ๋ฒ์
state_aggregates_df = (df
.groupBy("geo.state")
.agg(
avg("ecommerce.total_item_quantity").alias("avg_quantity"),
approx_count_distinct("user_id").alias("distinct_users")
)
)
display(state_aggregates_df)
์ง๊ณ ์ธ์๋ ์ด(column) ๋จ์ ์ํ ์ฐ์ฐ ํจ์๋ ์๋ค.
| ํจ์ | ์ค๋ช |
|---|---|
sqrt("์ด") | ์ ๊ณฑ๊ทผ |
cos("์ด") | ์ฝ์ฌ์ธ |
ceil("์ด") | ์ฌ๋ฆผ |
round("์ด") | ๋ฐ์ฌ๋ฆผ |
log("์ด") | ์์ฐ ๋ก๊ทธ |
from pyspark.sql.functions import cos, sqrt
display(
spark.range(10) # 0~9 ๋ฒ์์ id ์ด์ ๊ฐ์ง DataFrame ์์ฑ
.withColumn("sqrt", sqrt("id"))
.withColumn("cos", cos("id"))
)
groupBy ๋ฉ์๋์ ์ง๊ณ(avg, sum)์ ๋ด์ฅ ํจ์์ ์ง๊ณ(avg, sum)์ ์ฐจ์ด๋?A.
๋ ๋ค ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ด์ง๋ง, ๋ด์ฅ ํจ์ ๋ฐฉ์(agg + ๋ด์ฅ ํจ์)์ด ๋ ๊ฐ๋ ฅํ๋ค.
| ๊ตฌ๋ถ | ๋ฐฉ๋ฒ | ํน์ง |
|---|---|---|
| GroupedData ๋ฉ์๋ | .avg("์ด") | ๊ฐ๋จํ์ง๋ง, alias ๋ถ๊ฐ / ํ ๋ฒ์ ํ๋์ ์ง๊ณ๋ง ์ฝ๊ฒ ๊ฐ๋ฅ |
| ๋ด์ฅ ํจ์ + agg | .agg(avg("์ด").alias("๋ณ์นญ")) | alias ๊ฐ๋ฅ, ์ฌ๋ฌ ์ง๊ณ ๋์์, ๋ ๋ค์ํ ํจ์ ์ฌ์ฉ ๊ฐ๋ฅ |
alias๋ ์ ์ฐ๋๊ฐ?์ง๊ณ๋ฅผ ํ๋ฉด ์ด ์ด๋ฆ์ด avg(ecommerce.total_item_quantity) ์ฒ๋ผ ๊ธธ๊ณ ๋ชป์๊ธฐ๊ฒ ๋๋ค.
alias("avg_quantity") ๋ก ์ฝ๊ธฐ ์ข์ ์ด๋ฆ์ ๋ถ์ฌ์ฃผ๋ ๊ฒ์ด๋ค.
(์ง๋ฌธ์ ํ๋ฉด ์ด ์น์ ์ ์ถ๊ฐ๋ฉ๋๋ค)
[๋ฐ์ดํฐ ์ง๊ณ ์ ๋ต]
โ ๋จ์ ์ง๊ณ
df.groupBy("A").count()
df.groupBy("A").avg("B")
df.groupBy("A", "B").sum("C", "D")
โก agg + ๋ด์ฅ ํจ์ (์ถ์ฒ โญ)
from pyspark.sql.functions import avg, approx_count_distinct
df.groupBy("A").agg(
avg("B").alias("ํ๊ท B"),
approx_count_distinct("C").alias("๊ณ ์ C์")
)
โข ์ด ๋จ์ ์ํ ํจ์
from pyspark.sql.functions import sqrt, cos
df.withColumn("sqrt_id", sqrt("id"))
โ๏ธ ์ด์ ์ํ์ ๋๋ค. ์ง๋ฌธ ํ Q&A ์น์ ๊ณผ ์ค๋ช ์ด ๋ณด๊ฐ๋ ์์ ์ ๋๋ค.