Merge is so basic that it rarely shows up as a standalone problem. It is usually a part of a more complex problem. The most frequent pattern is merge + groupby.
pd.merge(A, B, on= 'aaa') where two tables have the same column name ‘aaa’.pd.merge(A, B, left_on = 'aaa', right_on = 'bbb') pd.merge(A, B, left_on = 'aaa', right_on = 'bbb', how = 'left') Forget right join. Industry standard is left join.pd.merge(A, B, left_on = 'aaa', right_on = 'bbb', how = 'inner') | SQL | pandas | 설명 |
|---|---|---|
GROUP BY col | .groupby('col') | starts with groupby() |
.reset_index(name = 'new_col') | usually the submission ends with this | |
COUNT(*) | .size() | counts all rows in each group |
COUNT(DISTINCT col) | .nunique() | counts unique values in each group |
SUM(col) | .sum() | 합계 |
AVG(col) | .mean() | 평균 |
AS new_col | .reset_index(name='new_col') or .agg() | 결과 컬럼명 지정 |
GROUP_CONCAT | .agg(lambda x: ','.join(...)) | 여러 행의 문자열을 하나로 통합 |
.groupby(), .nunique(), .reset_index(), rename(columns={})
import pandas as pd
def count_unique_subjects(teacher: pd.DataFrame) -> pd.DataFrame:
return teacher.groupby('teacher_id')['subject_id'].nunique().reset_index(name = 'cnt')
groupby with two indices, dictionary aggregator (named aggregation)
import pandas as pd
def daily_leads_and_partners(daily_sales: pd.DataFrame) -> pd.DataFrame:
return daily_sales.groupby(['date_id', 'make_name']).agg(
unique_leads=('lead_id', 'nunique'),
unique_partners=('partner_id', 'nunique')
).reset_index()
Mutate (add column) and then agg
import pandas as pd
def total_time(employees: pd.DataFrame) -> pd.DataFrame:
employees['time_spent'] = employees['out_time'] - employees['in_time']
return employees.groupby(['event_day', 'emp_id'])['time_spent'].sum().reset_index(name = 'total_time')[['event_day', 'emp_id', 'total_time']].rename(
columns = {
'event_day' : 'day'
}
)
agg by tuple with lambda x for complex string joining
import pandas as pd
def categorize_products(activities: pd.DataFrame) -> pd.DataFrame:
return activities.groupby('sell_date')['product'].agg(
[
('num_sold', 'nunique'),
('products', lambda x: ','.join(sorted(x.unique())))
# to Series.unique() outputs a python list
# sorted(list)
]
).reset_index()
TBD.
always think of null when merging
groupby() 완벽 이해하기Pandas의 groupby()는 데이터를 특정 키(컬럼)를 기준으로 그룹으로 나누고(Split), 각 그룹에 대해 함수를 적용해(Apply) 결과를 통합하는(Combine) 강력한 기능입니다. SQL의 GROUP BY와 유사하며, 요약 통계(평균, 합계, 개수 등)를 계산할 때 필수적으로 사용됩니다.
groupby()는 데이터를 분할하고, 연산하고, 합치는 Split-Apply-Combine 과정을 거칩니다.
sum(), mean(), count(), agg() 등)를 적용하여 데이터를 변환하거나 계산합니다.
.nunique()와 .reset_index() 데이터의 고유값 개수를 세는 nunique()는 실무에서 매우 자주 쓰입니다. groupby를 수행하면 그룹 키가 인덱스(Index)로 가기 때문에, 다시 일반 컬럼으로 돌려주는 reset_index()가 거의 세트처럼 따라다닙니다.
SQL:
SELECT teacher_id, COUNT(DISTINCT subject_id) AS cnt
FROM Teacher
GROUP BY teacher_id;
Pandas:
import pandas as pd
def count_unique_subjects(teacher: pd.DataFrame) -> pd.DataFrame:
return teacher.groupby('teacher_id')['subject_id'].nunique().reset_index(name='cnt')
여러 컬럼을 기준으로 그룹을 묶고, 각 집계 결과에 이름을 바로 붙여줄 때 유용합니다. agg(새컬럼명=('대상컬럼', '함수')) 형태의 튜플 구조를 사용합니다.
SQL:
SELECT date_id, make_name,
COUNT(DISTINCT lead_id) AS unique_leads,
COUNT(DISTINCT partner_id) AS unique_partners
FROM DailySales
GROUP BY date_id, make_name;
Pandas:
def daily_leads_and_partners(daily_sales: pd.DataFrame) -> pd.DataFrame:
return daily_sales.groupby(['date_id', 'make_name']).agg(
unique_leads=('lead_id', 'nunique'),
unique_partners=('partner_id', 'nunique')
).reset_index()
def orders_above_average(orders_details: pd.DataFrame) -> pd.DataFrame:
order_stats = orders_details.groupby('order_id').agg(
total_qty=('quantity', 'sum'),
# Use 'nunique' for unique products, or 'size' for total rows
product_count=('product_id', 'nunique'),
max_qty=('quantity', 'max')
).reset_index()
# 2. Safely calculate your custom weighted average
order_stats['custom_avg'] = order_stats['total_qty'] / order_stats['product_count']
# 3. Find the highest average
global_max_avg = order_stats['custom_avg'].max()
# 4. Filter and return
valid_orders = order_stats[order_stats['max_qty'] > global_max_avg]
return valid_orders[['order_id']]
그룹핑 전에 데이터를 먼저 가공(예: 시간 차이 계산)한 뒤 집계하는 패턴입니다.
SQL:
SELECT event_day AS day, emp_id, SUM(out_time - in_time) AS total_time
FROM Employees
GROUP BY event_day, emp_id;
Pandas:
def total_time(employees: pd.DataFrame) -> pd.DataFrame:
# 1. 먼저 각 행별로 시간 차이 계산 (Mutate)
employees['total_time'] = employees['out_time'] - employees['in_time']
# 2. 그룹핑 및 합계 계산
result = employees.groupby(['emp_id', 'event_day'])['total_time'].sum().reset_index()
# 3. 컬럼명 정리
return result.rename(columns={'event_day': 'day'})
단순한 합계나 평균이 아니라, “문자열을 콤마로 이어 붙이기” 같은 특수한 로직이 필요할 때 lambda와 agg를 조합합니다.
SQL (MySQL):
SELECT sell_date,
COUNT(DISTINCT product) AS num_sold,
GROUP_CONCAT(DISTINCT product ORDER BY product ASC SEPARATOR ',') AS products
FROM Activities
GROUP BY sell_date
ORDER BY sell_date;
Pandas:
def categorize_products(activities: pd.DataFrame) -> pd.DataFrame:
# agg 내에서 튜플과 lambda를 사용하여 복합 로직 적용
return activities.groupby('sell_date')['product'].agg([
('num_sold', 'nunique'),
('products', lambda x: ','.join(sorted(set(x))))
]).reset_index().sort_values('sell_date')
Pandas의 groupby()를 마스터하면 SQL에서 가능했던 모든 데이터 요약 작업을 파이썬에서도 효율적으로 처리할 수 있습니다!