Polars vs Pandas 2026๋ ๋น๊ต: ์ฑ๋ฅ, ๋ฌธ๋ฒ, ๋ฐ์ดํฐ ๋ถ์๊ฐ ๋ฉด์ ๋๋น
2026๋ Polars์ Pandas์ ์์ธ ๋น๊ต ๋ถ์์ ๋๋ค. ๋ฒค์น๋งํฌ ๊ฒฐ๊ณผ, ๋ฌธ๋ฒ ์ฐจ์ด, ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ, ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ ๋ถ์๊ฐ ๋ฉด์ ์์ ์์ฃผ ์ถ์ ๋๋ ์ง๋ฌธ๊ณผ ๋ชจ๋ฒ ๋ต๋ณ์ ๋ค๋ฃน๋๋ค.

Polars๋ Python ๋ฐ์ดํฐ ๋ถ์์์ ๊ณ ์ฑ๋ฅ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋น ๋ฅด๊ฒ ์๋ฆฌ์ก๊ณ ์์ต๋๋ค. ๋๊ท๋ชจ ๋ฐ์ดํฐ์ ์์ Pandas ๋๋น 10~15๋ฐฐ์ ์๋ ํฅ์์ ์ ๊ณตํ๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋๋ ํฌ๊ฒ ์ค์ ๋๋ค. 2026๋ 1์์ ์ถ์๋ Pandas 3.0์์ PyArrow๊ฐ ๊ธฐ๋ณธ ๋ฐฑ์๋๊ฐ ๋๋ฉด์ ํธ์์ฑ ๊ฒฉ์ฐจ๋ ์ค์ด๋ค์์ง๋ง, ์์ ์ฑ๋ฅ์์์ ์ฐจ์ด๋ ์ฌ์ ํ ํฝ๋๋ค.
Polars๋ 100๋ง ํ ์ด์์ ๋ฐ์ดํฐ์ , ETL ํ์ดํ๋ผ์ธ, ๋ฉ๋ชจ๋ฆฌ ์ ํ์ด ์๋ ํ๊ฒฝ์์ ๊ถ์ฅ๋ฉ๋๋ค. Pandas๋ Jupyter์์์ ํ์์ ๋ถ์, ๋ ๊ฑฐ์ ์ฝ๋๋ฒ ์ด์ค, ๋ค์ด์คํธ๋ฆผ ๋๊ตฌ๊ฐ Pandas DataFrame์ ์ง์ ํ์๋ก ํ๋ ๊ฒฝ์ฐ์ ์ ํฉํฉ๋๋ค.
๋ฒค์น๋งํฌ ๊ฒฐ๊ณผ: 2026๋ ์ค์ธก ์ฑ๋ฅ
ํ๋ก๋์ ๊ท๋ชจ์ ๋ฐ์ดํฐ์์์ ๋ฒค์น๋งํฌ๋ ์ผ๊ด๋ ํจํด์ ๋ณด์ฌ์ค๋๋ค. H2O.ai group-by ๋ฒค์น๋งํฌ์์ 1000๋ง ํ ๋ฐ์ดํฐ์ ๋ํด Polars๋ 0.45์ด์ ์๋ฃ๋๋ ๋ฐ๋ฉด, Pandas๋ 12.5์ด๊ฐ ์์๋ฉ๋๋ค. 10์ต ํ์์๋ Polars๊ฐ 45์ด์ ์คํธ๋ฆฌ๋ฐ ์ฒ๋ฆฌ๋ฅผ ์๋ฃํ์ง๋ง, Pandas๋ 64GB ๋จธ์ ์์ ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
| ์์ | Polars | Pandas | ์๋ ํฅ์ |
|---|---|---|---|
| Group-by (1000๋ง ํ) | 0.45์ด | 12.5์ด | 27๋ฐฐ |
| CSV ์ฝ๊ธฐ (1GB) | 2.1์ด | 10.5์ด | 5๋ฐฐ |
| Parquet ํํฐ (14GB) | 1.2์ด | 13.2์ด | 11๋ฐฐ |
| Join (1000๋ง ร 100๋ง ํ) | 1.8์ด | 19.4์ด | 10๋ฐฐ |
| ์ ๋ ฌ (1์ต ํ) | 4.2์ด | 46.1์ด | 11๋ฐฐ |
์ด ์์น๋ค์ ํฉ์ฑ ๋ง์ดํฌ๋ก๋ฒค์น๋งํฌ๊ฐ ์๋ ์ค์ ํ ์คํธ์์ ์ป์ ๊ฒ์ ๋๋ค. Polars PDS-H ๋ฒค์น๋งํฌ ์ค์ํธ์ ๋ฐ๋ฅด๋ฉด, Polars๋ CSV๋ฅผ 5๋ฐฐ ๋น ๋ฅด๊ฒ ์ฝ๊ณ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ 87% ์ค์ ๋๋ค.
# benchmark_comparison.py
import polars as pl
import pandas as pd
import time
# Polars: ์กฐ๊ฑด๋ถ ํธ์๋ค์ด์ด ํฌํจ๋ ์ง์ฐ ํ๊ฐ
start = time.perf_counter()
result_polars = (
pl.scan_parquet("sales_data_14gb.parquet") # ์ง์ฐ: ์์ง ๋ฐ์ดํฐ ๋ก๋ ์ ๋จ
.filter(pl.col("region") == "EMEA") # ์กฐ๊ฑด๋ถ๊ฐ ํ์ผ ๋ฆฌ๋์ ํธ์๋ค์ด
.group_by("product_category")
.agg(pl.col("revenue").sum())
.collect() # ์ฌ๊ธฐ์ ์คํ
)
polars_time = time.perf_counter() - start
# Pandas: ์ฆ์ ํ๊ฐ๋ก ์ ์ฒด ํ์ผ ๋ก๋
start = time.perf_counter()
df = pd.read_parquet("sales_data_14gb.parquet") # 14GB ์ ์ฒด๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋
result_pandas = (
df[df["region"] == "EMEA"] # ๋ก๋ ํ ํํฐ ์ ์ฉ
.groupby("product_category")["revenue"]
.sum()
)
pandas_time = time.perf_counter() - start
print(f"Polars: {polars_time:.2f}s | Pandas: {pandas_time:.2f}s")
# ์ผ๋ฐ์ ์ธ ์ถ๋ ฅ: Polars: 1.2s | Pandas: 13.2s์ด๋ฌํ ์ํคํ ์ฒ ์ฐจ์ด๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. Polars๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ CPU ์ฝ์ด์์ ์คํ๋๊ณ , Apache Arrow์ ์ปฌ๋ผ ๊ธฐ๋ฐ ๋ฉ๋ชจ๋ฆฌ ํ์์ ์ฌ์ฉํ๋ฉฐ, ์ฟผ๋ฆฌ๋ฅผ ์ง์ฐ ํ๊ฐํ์ฌ ์กฐ๊ฑด๋ถ๋ฅผ ํ์ผ ์ฝ๊ธฐ ์์ ์ ์ง์ ํธ์๋ค์ดํฉ๋๋ค.
ํต์ฌ ์ํคํ ์ฒ ์ฐจ์ด์
Pandas๋ ๋จ์ผ ์ฐจ์ ๋๋ก์ฒ๋ผ ์๋ํฉ๋๋ค. 16์ฝ์ด ํ๋ก์ธ์์์๋ Pandas๋ ๋ชจ๋ ํ์ ๋จ์ผ ๋ ์ธ์์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๋ฐ๋ฉด Polars๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ ์ฝ์ด์ ์์ ์ ์๋์ผ๋ก ๋ถ์ฐํฉ๋๋ค.
| ๊ธฐ๋ฅ | Polars | Pandas 3.0 |
|---|---|---|
| ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ธ | Apache Arrow ์ปฌ๋ผ ๊ธฐ๋ฐ | NumPy/PyArrow ํ์ด๋ธ๋ฆฌ๋ |
| ๋ณ๋ ฌ ์ฒ๋ฆฌ | ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฉํฐ์ค๋ ๋ | ์ฑ๊ธ์ค๋ ๋ |
| ํ๊ฐ ๋ฐฉ์ | ์ฟผ๋ฆฌ ์ต์ ํ ํฌํจ ์ง์ฐ ํ๊ฐ | ์ฆ์ ํ๊ฐ |
| ๋ฌธ์์ด ์ฒ๋ฆฌ | ๋ค์ดํฐ๋ธ Arrow ๋ฌธ์์ด | PyArrow ๋ฌธ์์ด (3.0์์ ์ ๊ท) |
| ๋ฉ๋ชจ๋ฆฌ ๋ณต์ฌ | ๊ฐ๋ฅํ ๊ฒฝ์ฐ ์ ๋ก ์นดํผ | Copy-on-Write (3.0์์ ์ ๊ท) |
| GPU ์ง์ | ์คํ์ (NVIDIA cuDF) | ์์ |
Pandas๋ ์์ ์ค ๋ฐ์ดํฐ๋ฅผ ์์ฃผ ๋ณต์ ํฉ๋๋ค. 2GB ํ์ผ์ด ๊ธฐ๋ณธ ๋ณํ์ ์ํํ๋ ๊ฒ๋ง์ผ๋ก๋ 8~10GB์ RAM์ด ํ์ํ ์ ์์ต๋๋ค. Polars๋ ๋ถ๋ณ ๋ฐ์ดํฐ ๋ชจ๋ธ๊ณผ ์ง์ฐ ํ๊ฐ๋ฅผ ํตํด ์ด๋ฌํ ๋ณต์ฌ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
์ง์ฐ ํ๊ฐ: Polars์ ์ต๋ ๊ฐ์
์ง์ฐ ํ๊ฐ๋ Polars์ ๊ฐ์ฅ ์ค์ํ ์ํคํ ์ฒ ์ด์ ์ ๋๋ค. ์์ ์ ์ฆ์ ์คํํ๋ ๋์ , Polars๋ ์ฟผ๋ฆฌ ํ๋์ ๊ตฌ์ถํ๊ณ ์คํ ์ ์ ์ต์ ํํฉ๋๋ค.
# lazy_evaluation_example.py
import polars as pl
# ์ง์ฐ ์ฟผ๋ฆฌ ์ ์ (์์ง ์คํ ์ ๋จ)
lazy_query = (
pl.scan_csv("transactions_50gb.csv") # LazyFrame: ์คํค๋ง๋ง, ๋ฐ์ดํฐ ์์
.filter(pl.col("amount") > 1000) # ์ฟผ๋ฆฌ ํ๋์ ์ถ๊ฐ
.filter(pl.col("status") == "completed") # ์ ํํฐ์ ๊ฒฐํฉ
.select(["transaction_id", "amount", "customer_id"]) # ํ๋ก์ ์
ํธ์๋ค์ด
.group_by("customer_id")
.agg([
pl.col("amount").sum().alias("total_spent"),
pl.col("transaction_id").count().alias("transaction_count")
])
)
# ์ต์ ํ๋ ์ฟผ๋ฆฌ ํ๋ ๋ณด๊ธฐ
print(lazy_query.explain())
# ํ์: ์กฐ๊ฑด๋ถ ํธ์๋ค์ด, ํ๋ก์ ์
ํธ์๋ค์ด, ํํฐ ๊ฒฐํฉ
# ์ค๋น๋๋ฉด ์คํ
result = lazy_query.collect()์ฟผ๋ฆฌ ์ตํฐ๋ง์ด์ ๋ ์ฌ๋ฌ ๋ณํ์ ์ ์ฉํฉ๋๋ค. ์กฐ๊ฑด๋ถ ํธ์๋ค์ด์ ํํฐ๋ฅผ ํ์ผ ๋ฆฌ๋ ์์ค์ผ๋ก ์ด๋์์ผ ํํฐ๋ง๋ ํ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋ค์ด๊ฐ์ง ์๋๋ก ํฉ๋๋ค. ํ๋ก์ ์ ํธ์๋ค์ด์ ํ์ํ ์ปฌ๋ผ๋ง ์ฝ๊ณ , ํํฐ ๊ฒฐํฉ์ ์ฌ๋ฌ ํํฐ ์์ ์ ๋จ์ผ ํจ์ค๋ก ๋ณํฉํฉ๋๋ค.
๋ง์ ์ปฌ๋ผ์ ๊ฐ์ง ๋์ ํ ์ด๋ธ์์์ I/O ์ง์ฝ์ ํ์ดํ๋ผ์ธ์์๋ Polars๊ฐ ํ์ผ ๋ฆฌ๋ ์์ค์์ ์ปฌ๋ผ์ ์์ ํ ๊ฑด๋๋ฐ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ ์ฐจ์ด๊ฐ ๋ ์ปค์ง๋๋ค.
Polars 1.x์๋ NVIDIA cuDF ํตํฉ์ ํตํ ์คํ์ GPU ์ง์์ด ํฌํจ๋์ด ์์ต๋๋ค. ํธํ๋๋ CUDA GPU๊ฐ ์๋ ๋จธ์ ์์ .collect()์ engine="gpu"๋ฅผ ์ ๋ฌํ๋ฉด ๋ฉ๋๋ค. ์ด ๊ธฐ๋ฅ์ ์ตํธ์ธ ๋ฐฉ์์ด๋ฉฐ ๋ชจ๋ ์์
์์ ์์ง ์์ ์ ์ด์ง ์์ต๋๋ค.
Pandas 3.0: ํธ์์ฑ ๊ฒฉ์ฐจ ์ค์ด๊ธฐ
2026๋ 1์์ ์ถ์๋ Pandas 3.0์ Polars์์ ์ฌ์ฉ์ฑ ๊ฒฉ์ฐจ๋ฅผ ์ค์ด๋ ์ค์ํ ๊ฐ์ ์ฌํญ์ ์ ๊ณตํ์ง๋ง, ์์ ์ฑ๋ฅ์์๋ ์ฌ์ ํ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
# pandas_3_new_features.py
import pandas as pd
# PyArrow ๋ฌธ์์ด ๋ฐฑ์๋๊ฐ ๊ธฐ๋ณธ๊ฐ (๋ฌธ์์ด ์์
5~10๋ฐฐ ๋น ๋ฆ)
df = pd.read_csv("users.csv") # ๋ฌธ์์ด์ด ์ด์ ๊ธฐ๋ณธ์ ์ผ๋ก string[pyarrow]
# ์๋ก์ด ํํ์ ๋น๋ (Polars ๊ตฌ๋ฌธ๊ณผ ์ ์ฌ)
result = df.select(
pd.col("name").str.upper(),
pd.col("age") * 2,
(pd.col("salary") > 100000).alias("high_earner")
)
# Copy-on-Write๋ก SettingWithCopyWarning ํด๊ฒฐ
subset = df[df["age"] > 30] # ๋ณต์ฌ๊ฐ ์๋ ๋ทฐ ๋ฐํ
subset = subset.copy() # ๋ณ๊ฒฝ์๋ ๋ช
์์ ๋ณต์ฌ ํ์
# ์๋ก์ด Arrow ์ํธ ์ด์ฉ ๋ฉ์๋
import pyarrow as pa
arrow_table = pa.table({"x": [1, 2, 3]})
df = pd.DataFrame.from_arrow(arrow_table) # ์ ๋ก ์นดํผ ์ํฌํธPandas 3.0์ ์ฃผ์ ๋ณ๊ฒฝ ์ฌํญ:
- PyArrow ๋ฌธ์์ด ๋ฐฑ์๋: ๋ฌธ์์ด ์ปฌ๋ผ์ด ๊ธฐ๋ณธ์ ์ผ๋ก
string[pyarrow]๋ฅผ ์ฌ์ฉํ์ฌ ํ ์คํธ ์ค์ฌ ๋ฐ์ดํฐ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ 50% ์ ๊ฐ - Copy-on-Write ๊ฐ์ :
df[col]์ ๋ทฐ๋ฅผ ๋ฐํํ๊ณ , ๋ณ๊ฒฝ์๋ ๋ช ์์ ์ธ.copy()๊ฐ ํ์ pd.col()ํํ์ ๋น๋: ๋ฉ์๋ ์ฒด์ด๋์ ์ํ Polars์์ ์๊ฐ๋ฐ์ ์ ๊ตฌ๋ฌธ- ํ๊ธฐ๋ ๋ฉ์๋ ์ ๊ฑฐ:
append(), ๋๋ถ๋ถ์ ๋ฉ์๋์์inplace=True,[]๋ฅผ ์ฌ์ฉํ ์์น ์ธ๋ฑ์ฑ
Data Analytics ๋ฉด์ ์ค๋น๊ฐ ๋์ จ๋์?
์ธํฐ๋ํฐ๋ธ ์๋ฎฌ๋ ์ดํฐ, flashcards, ๊ธฐ์ ํ ์คํธ๋ก ์ฐ์ตํ์ธ์.
๊ตฌ๋ฌธ ๋น๊ต: ์ผ๋ฐ์ ์ธ ์์
๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ตฌ๋ฌธ์ ํฌ๊ฒ ๋ค๋ฆ ๋๋ค. Polars๋ ๋ช ์์ ์ธ ์ปฌ๋ผ ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ ๋ฉ์๋ ์ฒด์ด๋์ ์ฌ์ฉํ๊ณ , Pandas๋ ๋ธ๋ํท ํ๊ธฐ๋ฒ์ ๋ ์์กดํฉ๋๋ค.
ํํฐ๋ง๊ณผ ์ ํ
# filtering_comparison.py
import polars as pl
import pandas as pd
# ์ํ ๋ฐ์ดํฐ
data = {
"name": ["Alice", "Bob", "Charlie", "Diana"],
"department": ["Engineering", "Sales", "Engineering", "HR"],
"salary": [95000, 72000, 88000, 65000],
"years": [5, 3, 7, 2]
}
# POLARS: pl.col()์ ์ฌ์ฉํ ๋ช
์์ ์ปฌ๋ผ ์ฐธ์กฐ
df_pl = pl.DataFrame(data)
result_pl = (
df_pl
.filter(pl.col("department") == "Engineering") # pl.col()๋ก ํํฐ
.filter(pl.col("salary") > 80000) # ํํฐ ์ฒด์ด๋
.select(["name", "salary"]) # ์ปฌ๋ผ ์ ํ
)
# PANDAS: ๋ธ๋ํท ํ๊ธฐ๋ฒ
df_pd = pd.DataFrame(data)
result_pd = (
df_pd
.loc[df_pd["department"] == "Engineering"] # ํํฐ์ loc
.loc[lambda x: x["salary"] > 80000] # ์ฒด์ด๋์ ๋๋ค
[["name", "salary"]] # ์ ํ์ ๋ธ๋ํท
)์ง๊ณ์ Group By
# aggregation_comparison.py
# POLARS: ํํ๋ ฅ ์๋ ์ง๊ณ ๊ตฌ๋ฌธ
result_pl = (
df_pl
.group_by("department")
.agg([
pl.col("salary").mean().alias("avg_salary"),
pl.col("salary").max().alias("max_salary"),
pl.col("name").count().alias("headcount"),
(pl.col("salary") * pl.col("years")).sum().alias("total_compensation_years")
])
)
# PANDAS: ๋ช
๋ช
๋ ์ง๊ณ ๊ตฌ๋ฌธ
result_pd = (
df_pd
.groupby("department")
.agg(
avg_salary=("salary", "mean"),
max_salary=("salary", "max"),
headcount=("name", "count"),
total_compensation_years=("salary", lambda x: (df_pd.loc[x.index, "salary"] * df_pd.loc[x.index, "years"]).sum())
)
)์กฐ์ธ (Join)
# joins_comparison.py
employees = pl.DataFrame({
"emp_id": [1, 2, 3],
"name": ["Alice", "Bob", "Charlie"],
"dept_id": [10, 20, 10]
})
departments = pl.DataFrame({
"dept_id": [10, 20, 30],
"dept_name": ["Engineering", "Sales", "HR"]
})
# POLARS: ๋ช
์์ ์กฐ์ธ ๊ตฌ๋ฌธ
result_pl = employees.join(
departments,
on="dept_id", # ์กฐ์ธ ์ปฌ๋ผ
how="left" # ์กฐ์ธ ์ ํ: left, inner, outer, cross, semi, anti
)
# PANDAS: merge ํจ์
result_pd = pd.merge(
employees.to_pandas(),
departments.to_pandas(),
on="dept_id",
how="left"
)2026๋ ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ์๊ธฐ
์ ํ์ ๋ฐ์ดํฐ์ ํฌ๊ธฐ, ๊ธฐ์กด ์ธํ๋ผ, ๋ค์ด์คํธ๋ฆผ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค.
Polars๋ฅผ ์ ํํด์ผ ํ ๋:
- 100๋ง ํ ์ด์์ ๋ฐ์ดํฐ์ ์ ๋ค๋ฃฐ ๋
- ETL ํ์ดํ๋ผ์ธ์ด๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์์ ์ ๊ตฌ์ถํ ๋
- ๋ฐ์ดํฐ ํฌ๊ธฐ์ ๋นํด ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ํ๋ ๋
- ์ฑ๋ฅ์ด ์ค์ํ ๋ (์ค์๊ฐ ๋ถ์, ๋ฐฐ์น ์ฒ๋ฆฌ)
- ๋ ๊ฑฐ์ ์ข ์์ฑ์ด ์๋ ์ ํ๋ก์ ํธ๋ฅผ ์์ํ ๋
Pandas๋ฅผ ์ ํํด์ผ ํ ๋:
- Jupyter ๋ ธํธ๋ถ์์ ๋น ๋ฅธ ํ์
- ์ฑ๋ฅ ์ฐจ์ด๊ฐ ๋ฌด์ํ ์ ์๋ ์๊ท๋ชจ ๋ฐ์ดํฐ์ (100๋ง ํ ๋ฏธ๋ง)
- ๋ค์ด์คํธ๋ฆผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ Pandas DataFrame์ ํ์๋ก ํ ๋ (scikit-learn, statsmodels, matplotlib)
- Pandas๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ ๊ธฐ์กด ์ฝ๋๋ฒ ์ด์ค ์ ์ง ๋ณด์
- ํ ์น์๋๊ฐ ์ฑ๋ฅ ์๊ตฌ ์ฌํญ๋ณด๋ค ์ค์ํ ๋
2026๋ ์ ์ค์ฉ์ ์ธ ํจํด์ ๋ ๋ค ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. Polars๋ก ๋ฌด๊ฑฐ์ด ๋ณํ์ ์ํํ๊ณ , ML ๋ฐ ํ๋กํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ ๊ฒฝ๊ณ์์ Pandas๋ฅผ ์ฌ์ฉํฉ๋๋ค.
# hybrid_workflow.py
import polars as pl
from sklearn.ensemble import RandomForestClassifier
import matplotlib.pyplot as plt
# Polars๋ก ๋ฌด๊ฑฐ์ด ๋ฐ์ดํฐ ์ฒ๋ฆฌ (10๋ฐฐ ๋น ๋ฆ)
df = (
pl.scan_parquet("raw_data/*.parquet")
.filter(pl.col("valid") == True)
.with_columns([
(pl.col("revenue") / pl.col("quantity")).alias("unit_price"),
pl.col("timestamp").dt.month().alias("month")
])
.group_by(["customer_id", "month"])
.agg([
pl.col("revenue").sum(),
pl.col("quantity").mean()
])
.collect()
)
# ML์ฉ Pandas๋ก ๋ณํ (์ซ์ ์ปฌ๋ผ์ ์ ๋ก ์นดํผ)
X = df.select(["revenue", "quantity"]).to_pandas()
y = df.select("churn").to_pandas().values.ravel()
# scikit-learn์ Pandas/NumPy๋ฅผ ๊ธฐ๋
model = RandomForestClassifier()
model.fit(X, y)
# Pandas ํตํฉ์ผ๋ก ํ๋กํ
df.to_pandas().plot(kind="bar", x="month", y="revenue")
plt.savefig("monthly_revenue.png")๋ฐ์ดํฐ ๋ถ์๊ฐ ๋ฉด์ ์์์ Polars vs Pandas ์ง๋ฌธ
์ด๋ฌํ ์ง๋ฌธ๋ค์ ํ๋ณด์๊ฐ Python ๋ฐ์ดํฐ ๋ถ์ ์คํฌ์ ์ธ๊ธํ ๋ ๋ฐ์ดํฐ ๋ถ์๊ฐ ๋ฐ ๋ฐ์ดํฐ ์์ง๋์ด ๋ฉด์ ์์ ์์ฃผ ์ถ์ ๋ฉ๋๋ค.
์ง๋ฌธ 1: Pandas๋ณด๋ค Polars๋ฅผ ์ ํํ๋ ๊ฒฝ์ฐ๋ ์ธ์ ์ ๋๊น?
์ข์ ๋ต๋ณ: Polars๋ ์ง์ฐ ํ๊ฐ, ๋ฉํฐ์ค๋ ๋ ์คํ, Apache Arrow ๋ฉ๋ชจ๋ฆฌ ํ์์ผ๋ก ์ธํด 100๋ง ํ ์ด์์ ๋ฐ์ดํฐ์ ์์ Pandas๋ฅผ ํฌ๊ฒ ๋ฅ๊ฐํฉ๋๋ค. ์ ํ์ ์ธ ๊ฐ์ง ์์์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค: ๋ฐ์ดํฐ ๋ณผ๋ฅจ (๋๊ท๋ชจ ๋ฐ์ดํฐ์ ์๋ Polars), ํ์ดํ๋ผ์ธ ์๊ตฌ ์ฌํญ (ETL์๋ Polars), ์ํ๊ณ ์ ์ฝ (scikit-learn์ด๋ matplotlib ํตํฉ์ด ๋ง์ผ๋ฉด Pandas). ํ์ด๋ธ๋ฆฌ๋ ์ ๊ทผ ๋ฐฉ์์ด ํจ๊ณผ์ ์ ๋๋ค: ๋ณํ์๋ Polars, ML ๊ฒฝ๊ณ์์๋ Pandas.
์ง๋ฌธ 2: Polars์ ์ง์ฐ ํ๊ฐ๋ฅผ ์ค๋ช ํ์ธ์
์ข์ ๋ต๋ณ: ์ง์ฐ ํ๊ฐ๋ .collect()๊ฐ ํธ์ถ๋ ๋๊น์ง ๊ณ์ฐ์ ์ฐ๊ธฐํฉ๋๋ค. Polars๋ ์ฟผ๋ฆฌ ํ๋์ ๊ตฌ์ถํ ๋ค์ ์กฐ๊ฑด๋ถ ํธ์๋ค์ด (ํํฐ๋ฅผ ํ์ผ ๋ฆฌ๋๋ก ์ด๋), ํ๋ก์ ์
ํธ์๋ค์ด (ํ์ํ ์ปฌ๋ผ๋ง ์ฝ๊ธฐ), ์์
์ตํฉ์ ํตํด ์ต์ ํํฉ๋๋ค. ์ด๋ 50GB Parquet ํ์ผ์ ๋ํ ํํฐ๊ฐ ์ ์ฒด ํ์ผ์ด ์๋ ์ผ์นํ๋ ํ๋ง ์ฝ๋๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. LazyFrame.explain() ๋ฉ์๋๋ก ์ต์ ํ๋ ํ๋์ ํ์ธํ ์ ์์ต๋๋ค.
์ง๋ฌธ 3: Pandas 3.0์์ ๋ฌด์์ด ๋ฐ๋์์ต๋๊น?
์ข์ ๋ต๋ณ: Pandas 3.0 (2026๋
1์)์ ๊ธฐ๋ณธ์ ์ผ๋ก Copy-on-Write๋ฅผ ๊ฐ์ ํ๊ณ , ๋ฌธ์์ด ์์
์ 5~10๋ฐฐ ๋น ๋ฅด๊ฒ ํ๋ PyArrow๋ฅผ ๋ฌธ์์ด ๋ฐฑ์๋๋ก ์ฌ์ฉํ๋ฉฐ, append() ๋ฐ inplace=True์ ๊ฐ์ ํ๊ธฐ๋ ๋ฉ์๋๋ฅผ ์ ๊ฑฐํ์ต๋๋ค. ์๋ก์ด pd.col() ํํ์ ๋น๋๋ Polars์ ์ ์ฌํ ๊ตฌ๋ฌธ์ ์ ๊ณตํฉ๋๋ค. Python 3.11์ด ์ต์ ์๊ตฌ ๋ฒ์ ์
๋๋ค.
์ง๋ฌธ 4: ๋ฉ๋ชจ๋ฆฌ์ ๋ง์ง ์๋ 50GB CSV ํ์ผ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ์๊ฒ ์ต๋๊น?
# interview_answer_large_file.py
import polars as pl
# ์ต์
1: ์คํธ๋ฆฌ๋ฐ์ ์ฌ์ฉํ ์ง์ฐ ํ๊ฐ (Polars)
result = (
pl.scan_csv("large_file.csv") # ์คํค๋ง๋ง ์ฝ์
.filter(pl.col("status") == "active")
.group_by("region")
.agg(pl.col("revenue").sum())
.collect(streaming=True) # ๋ฐฐ์น๋ก ์ฒ๋ฆฌ
)
# ์ต์
2: ์ฒญํฌ ์ฒ๋ฆฌ (Pandas ํด๋ฐฑ)
import pandas as pd
results = []
for chunk in pd.read_csv("large_file.csv", chunksize=1_000_000):
filtered = chunk[chunk["status"] == "active"]
agg = filtered.groupby("region")["revenue"].sum()
results.append(agg)
final = pd.concat(results).groupby(level=0).sum()์ข์ ๋ต๋ณ: Polars ์ ๊ทผ ๋ฐฉ์์ด ๊ถ์ฅ๋ฉ๋๋ค. ์คํธ๋ฆฌ๋ฐ์ ์ฌ์ฉํ ์ง์ฐ ํ๊ฐ๋ ๋ฐ์ดํฐ๋ฅผ ์๋์ผ๋ก ๋ฐฐ์น ์ฒ๋ฆฌํ๊ณ , ํ์ผ ๋ฆฌ๋ ์์ค์์ ์กฐ๊ฑด๋ถ ํธ์๋ค์ด์ ์ ์ฉํ๋ฉฐ, ์ฝ์ด ๊ฐ์ ๋ณ๋ ฌํํฉ๋๋ค. Pandas์ ์ฒญํฌ ์ ๊ทผ ๋ฐฉ์์ ์๋ํ์ง๋ง ์๋ ๋ฐฐ์น ๊ด๋ฆฌ๊ฐ ํ์ํ๊ณ ์ฒญํฌ ๊ฐ ์ต์ ํ๊ฐ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
์ง๋ฌธ 5: ์ด Pandas ์ฝ๋๋ฅผ Polars๋ก ๋ณํํ์ธ์
# interview_conversion.py
# ์ฃผ์ด์ง Pandas ์ฝ๋
df = pd.read_csv("sales.csv")
df["year"] = pd.to_datetime(df["date"]).dt.year
result = (
df[df["amount"] > 1000]
.groupby(["region", "year"])
.agg({"amount": ["sum", "mean"], "customer_id": "nunique"})
)
# Polars ๋๋ฑ ์ฝ๋
result = (
pl.scan_csv("sales.csv") # ์ต์ ํ๋ฅผ ์ํด ์ง์ฐ
.with_columns(
pl.col("date").str.to_datetime().dt.year().alias("year")
)
.filter(pl.col("amount") > 1000)
.group_by(["region", "year"])
.agg([
pl.col("amount").sum().alias("amount_sum"),
pl.col("amount").mean().alias("amount_mean"),
pl.col("customer_id").n_unique().alias("unique_customers")
])
.collect()
)๋ฉด์ ๊ด์ ๋จ์ํ ๊ตฌ๋ฌธ ๋ณํ์ด ์๋๋ผ ์ง์ฐ ํ๊ฐ๊ฐ ์ธ์ ์ค์ํ์ง์ ๋ํ ์ดํด๋ฅผ ์ฐพ์ต๋๋ค. scan_csv๊ฐ ์กฐ๊ฑด๋ถ ํธ์๋ค์ด์ ํ์ฑํํ์ฌ amount > 1000 ํํฐ๊ฐ ํ์ผ ๋ฆฌ๋ ์์ค์์ ์ ์ฉ๋๋ค๋ ์ ์ ์ธ๊ธํ์ธ์.
๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต: Pandas์์ Polars๋ก
๊ธฐ์กด Pandas ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๋ง์ด๊ทธ๋ ์ด์ ํ๋ ค๋ฉด ์์ ํ ์ฌ์์ฑ์ด ์๋ ์ ์ง์ ์ธ ๋์ ์ด ํ์ํฉ๋๋ค.
# migration_strategy.py
import polars as pl
import pandas as pd
# ๋จ๊ณ 1: ๋น ๋ฅธ ํ์์๋ Pandas ์ ์ง
def explore_data(path: str) -> pd.DataFrame:
return pd.read_csv(path).head(1000)
# ๋จ๊ณ 2: ๋ฌด๊ฑฐ์ด ๋ณํ์ Polars ๋์
def process_data(path: str) -> pl.DataFrame:
return (
pl.scan_csv(path)
.filter(pl.col("valid") == True)
.with_columns([
(pl.col("price") * pl.col("quantity")).alias("total")
])
.collect()
)
# ๋จ๊ณ 3: ํ์ํ ๊ฒฝ๊ณ์์ ๋ณํ
def train_model(df_polars: pl.DataFrame):
df_pandas = df_polars.to_pandas() # ์ซ์๋ ์ ๋ก ์นดํผ
# scikit-learn ์ฝ๋ ์ฌ๊ธฐ์
# ๋จ๊ณ 4: ํซ ํจ์ค๋ฅผ ์ ์ง์ ์ผ๋ก ๊ต์ฒด
# ํ๋กํ์ผ๋ง์ผ๋ก ๋๋ฆฐ Pandas ์์
์๋ณ
# ํ ๋ฒ์ ํ๋์ ํจ์์ฉ Polars ๋๋ฑ๋ฌผ๋ก ๊ต์ฒดH2O.ai๋ 2026๋ Driverless AI ๋ฆด๋ฆฌ์ค์์ Pandas์์ Polars๋ก ์ ํํ ํ ํ ์ด๋ธ ํ์ AutoML ์คํ์์ 6๋ฐฐ์ ์๋ํฌ์๋ ์ ํด๋ก ๊ฐ์ ์ ๋ฌธ์ํํ์ต๋๋ค.
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
ํ๋ก๋์ ๊ณผ ๋ฉด์ ์ ์ํ ํต์ฌ ํฌ์ธํธ
- Polars๋ ์ง์ฐ ํ๊ฐ, ๋ฉํฐ์ค๋ ๋ ์คํ, Apache Arrow ๋ฉ๋ชจ๋ฆฌ ํ์์ ํตํด 100๋ง ํ ์ด์์ ๋ฐ์ดํฐ์ ์์ Pandas๋ณด๋ค 10~15๋ฐฐ ๋น ๋ฅธ ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค
- Pandas 3.0 (2026๋ 1์)์ PyArrow ๋ฌธ์์ด๊ณผ Copy-on-Write๋ฅผ ๋์ ํ์ฌ ํธ์์ฑ ๊ฒฉ์ฐจ๋ฅผ ์ค์์ง๋ง ์ฑ๋ฅ ๊ฒฉ์ฐจ๋ ์ค์ด์ง ๋ชปํ์ต๋๋ค
- ์ง์ฐ ํ๊ฐ๋ ์กฐ๊ฑด๋ถ ํธ์๋ค์ด๊ณผ ํ๋ก์ ์ ํธ์๋ค์ด์ ๊ฐ๋ฅํ๊ฒ ํ์ฌ, ํํฐ์ ์ปฌ๋ผ ์ ํ์ด ๋ฐ์ดํฐ๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ๋ค์ด๊ฐ๊ธฐ ์ ํ์ผ ๋ฆฌ๋ ์์ค์์ ๋ฐ์ํฉ๋๋ค
- 2026๋ ์๋ ํ์ด๋ธ๋ฆฌ๋ ํจํด์ด ์ฃผ๋ฅ: ๋ฐ์ดํฐ ์ฒ๋ฆฌ์๋ Polars, ML ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๊ณ์๋ Pandas
- ๋ฉด์ ์ง๋ฌธ์ ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ธ์ ์ฌ์ฉํ ์ง, ์ง์ฐ ํ๊ฐ ๋ฉ์ปค๋์ฆ, ์ค์ฉ์ ์ธ ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต์ ์ด์ ์ ๋ง์ถฅ๋๋ค
- 100๋ง ํ ๋ฏธ๋ง์ ๋ฐ์ดํฐ์ ์์๋ ์ฑ๋ฅ ์ฐจ์ด๊ฐ ์ข ์ข ๋ฌด์ํ ์ ์์ผ๋ฉฐ, ํ ์น์๋๊ฐ ๊ฒฐ์ ์์ธ์ด ๋ฉ๋๋ค
- Polars 1.x๋ 5์ต 7500๋ง ์ด์์ ๋ค์ด๋ก๋, 1800๋ง ์ ๋ก ์๋ฆฌ์ฆ A ํ๋ฉ์ ๋ฐ์์ผ๋ฉฐ, ํํ๋ฐ์ดํธ ๊ท๋ชจ์ ๋ฐ์ดํฐ์ ์ ์ฒ๋ฆฌํ๋ ๊ธฐ์ ์์ ์ฌ์ฉ๋์ด ํ๋ก๋์ ์ ์ค๋น๋์ด ์์ต๋๋ค
Data Analytics ์ฝ๋์ ๋ฒ๊ทธ๋ฅผ ์ฐพ์ ์ ์๋์
์ค์ ์ฝ๋ ํ ์กฐ๊ฐ, ์จ์ ๋ฒ๊ทธ ํ๋, ํ๋ฃจ ํ ๋ฒ. ๊ณ์ ์์ด ๋ฐ๋ก ๋์ ํ ์ ์์ต๋๋ค.

์์ฑ์
Anthony Fillion-MailletSharpSkill ์ฐฝ์ ์
10๋ ์ด์ ํ์คํ ๊ฐ๋ฐ์ ํด์์ต๋๋ค. SharpSkill์ ์ด์ํ๋ฉฐ ์ด๊ณณ์ ๊ฒ์๋๋ ๋ชจ๋ ๋ด์ฉ์ ์ฑ ์์ ์ง๋๋ค.
2026๋ 8์ 21์ผ ์ ๋ฐ์ดํธ
ํ๊ทธ
๊ณต์
๊ด๋ จ ๊ธฐ์ฌ

Pandas 3.0 ์๋ฒฝ ๊ฐ์ด๋(2026): ์๋ก์ด API, ์ฃผ์ ๋ณ๊ฒฝ์ฌํญ, ๋ฉด์ ์ง๋ฌธ ์ด์ ๋ฆฌ
Pandas 3.0์ Copy-on-Write, PyArrow ๋ฌธ์์ด ๋ฐฑ์๋, pd.col() ํํ์ ๋น๋ ๋ฑ ํต์ฌ ๋ณ๊ฒฝ์ฌํญ์ ์์ธํ ๋ถ์ํฉ๋๋ค. ๋ฐ์ดํฐ ๋ถ์ ์์ง๋์ด ๋ฉด์ ์์ ์ถ์ ๋๋ ํต์ฌ ์ง๋ฌธ๋ ํจ๊ป ๋ค๋ฃน๋๋ค.

2026๋ ์ดํ๋ฆฌ์ ๋ฐ์ดํฐ ๋ถ์๊ฐ ๋ฉด์ ์ง๋ฌธ: SQL, Python, ๋ถ์ ์คํฌ ์์ ๊ฐ์ด๋
2026๋ ์ดํ๋ฆฌ์์์ ๋ฐ์ดํฐ ๋ถ์๊ฐ๋ก ์ทจ์ ํ๊ธฐ ์ํ ๋ฉด์ ์ค๋น ๊ฐ์ด๋์ ๋๋ค. SQL, Python, pandas, ๋น์ฆ๋์ค ๋ถ์์ ๊ดํ ์์ฃผ ์ถ์ ๋๋ ์ง๋ฌธ๊ณผ ๋ชจ๋ฒ ๋ต๋ณ์ ์์ธํ ์ค๋ช ํฉ๋๋ค.

๋ฐ์ดํฐ ๋ถ์๊ฐ ๋ฉด์ ์ง๋ฌธ 2026๋ ์๋ฒฝ ๊ฐ์ด๋: SQL, Python, ๋ถ์ ์คํฌ
2026๋ ๋ฐ์ดํฐ ๋ถ์๊ฐ ๋ฉด์ ์์ ์์ฃผ ์ถ์ ๋๋ SQL, Python, ํต๊ณ ๋ถ์ ์ง๋ฌธ๊ณผ ๋ชจ๋ฒ ๋ต๋ณ์ ์์ธํ ๋ค๋ฃน๋๋ค. ์ค์ ์ฝ๋ ์์ ์ ํต์ฌ ํฌ์ธํธ๋ก ์ทจ์ ์ฑ๊ณต์ ์ค๋นํฉ๋๋ค.