01 사용자 정의함수
-01 lambda
-02 def
-03 리스트 내포표현식 (List Comprehension)
02 groupby
-01 groupby 연산
-02 외부 객체를 사용한 그룹핑
03 조인 (merge)
01 사용자 정의함수
-01 lambda
비교적 간단한 연산 결과 및 리턴값을 가지는 함수를 작성할 때 사용한다.
변수선언, 자료구조 탐색 및 생성 등의 연산이 불가능하다.
* 사용법)
함수명 = lambda input : output
함수명 = lambda input : 참리턴 if 조건 else 거짓리턴
함수명 = lambda input : 참리턴1 if 조건1 else 참리턴2 if 조건2 else 거짓리턴 (권고 X)
▲ 지나치게 복잡해지며 가독성이 떨어지는 문제가 발생하기 시작한다.
* default 값 설정하기)
f_sum = lambda x, y=0 : x + y # default 값 설정을 통해 y를 생략할 수 있다.
f_sum(1,10)
f_sum(1)
※ default 값 설정 시 주의사항)
f_sum = lambda x=0, y : x + y
f_sum = lambda x=0, y : x + y
Cell In[87], line 1
f_sum = lambda x=0, y : x + y
^
SyntaxError: parameter without a default follows parameter with a default
▲ 파이썬에서는 함수의 기본값 선언 시 앞의 인수가 기본값을 가지는 경우 반드시 그 뒤의 모 든 인수들이 기본값을 가져야 한다.
따라서 기본값 선언 시 뒤의 인수부터 순차적으로 지정하는 것이 좋다.
-02 def
def 함수명(input1, input2, ...) :
본문(변수선언, for문, if문, ...)
return 대상
* defalut 값 설정하기)
def f_sub(x, y=0) :
return x - y
f_sub(10,5)
f_sub(10)
ex) emp에서 10번 인사부, 그 외 총무부
import pandas as pd
emp = pd.read_csv('emp.csv')
# 방법1) lambda
emp['DEPTNO'][0]
# 조건을 통해 확인 후 출력하기 때문에 상수만이 사용 가능하다.
f1 = lambda x : '인사부' if x == 10 else '총무부'
# 상수의 경우 정상적으로 출력됨을 확인할 수 있다.
f1(10) # 정상
f1(30) # 정상
f1(10) # 정상
Out[41]: '인사부'
f1(30) # 정상
Out[42]: '총무부'
# 따라서 Series가 들어가면 오류가 발생한다.
f1(emp['DEPTNO']) # 불가
f1(emp['DEPTNO']) # 불가
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_23264\70618826.py in ?()
----> 1 f1(emp['DEPTNO']) # 불가
~\AppData\Local\Temp\ipykernel_23264\2778421134.py in ?(x)
----> 1 f1 = lambda x : '인사부' if x == 10 else '총무부'
~\anaconda3\Lib\site-packages\pandas\core\generic.py in ?(self)
1578 @final
1579 def __nonzero__(self) -> NoReturn:
-> 1580 raise ValueError(
1581 f"The truth value of a {type(self).__name__} is ambiguous. "
1582 "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
1583 )
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
emp['DEPTNO'].map(f1) # 정상
emp['DEPTNO'].map(f1) # 정상
Out[44]:
0 총무부
1 총무부
2 총무부
3 총무부
4 총무부
5 총무부
6 인사부
7 총무부
8 인사부
9 총무부
10 총무부
11 총무부
12 총무부
13 인사부
Name: DEPTNO, dtype: object
# 방법2) def
def f2(x) :
if x == 10 :
dname = '인사부'
else :
dname = '총무부'
return dname
f2(10)
f2(10)
Out[46]: '인사부'
f2(emp['DEPTNO'])
f2(emp['DEPTNO'])
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_23264\1340034630.py in ?()
----> 1 f2(emp['DEPTNO'])
~\AppData\Local\Temp\ipykernel_23264\653499240.py in ?(x)
1 def f2(x) :
----> 2 if x == 10 :
3 dname = '인사부'
4 else :
5 dname = '총무부'
~\anaconda3\Lib\site-packages\pandas\core\generic.py in ?(self)
1578 @final
1579 def __nonzero__(self) -> NoReturn:
-> 1580 raise ValueError(
1581 f"The truth value of a {type(self).__name__} is ambiguous. "
1582 "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
1583 )
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
emp['DEPTNO'].map(f2)
마찬가지로 상수가 들어가야하는 상황이기에 map 매서드를 이용해야 정상적인 결과가 리턴됨을 확인할 수 있다.
emp['DEPTNO'].map(f2)
Out[48]:
0 총무부
1 총무부
2 총무부
3 총무부
4 총무부
5 총무부
6 인사부
7 총무부
8 인사부
9 총무부
10 총무부
11 총무부
12 총무부
13 인사부
Name: DEPTNO, dtype: object
# 방법3) def + for
def f3(x):
dname = []
for i in x:
if i == 10:
dname.append('인사부')
else:
dname.append('총무부')
return pd.Series(dname)
f3(emp['DEPTNO'])
f3(emp['DEPTNO'])
Out[70]:
0 총무부
1 총무부
2 총무부
3 총무부
4 총무부
5 총무부
6 인사부
7 총무부
8 인사부
9 총무부
10 총무부
11 총무부
12 총무부
13 인사부
dtype: object
# 방법1) lambda
f1 = lambda x : 'A' if x >= 3000 else 'B'
emp['SAL'].map(f1)
emp['SAL'].map(f1)
Out[73]:
0 B
1 B
2 B
3 B
4 B
5 B
6 B
7 A
8 A
9 B
10 B
11 B
12 A
13 B
Name: SAL, dtype: object
# 방법2) def
def f2(x) :
if x >= 3000 :
GRADE = 'A'
else :
GRADE = 'B'
return GRADE
# 또는 x가 아니라 좀 더 직관적으로 sal 등으로 지정하는 것도 좋다.
def f_sal2(sal) :
if sal >= 3000 :
grade = 'A'
else :
grade = 'B'
return grade
emp['SAL'].map(f2)
emp['SAL'].map(f2)
Out[80]:
0 B
1 B
2 B
3 B
4 B
5 B
6 B
7 A
8 A
9 B
10 B
11 B
12 A
13 B
Name: SAL, dtype: object
# 방법3) def + for
def f3(x) :
GRADE = []
for i in x :
if i >= 3000 :
GRADE.append('A')
else :
GRADE.append('B')
return pd.Series(GRADE)
f3(emp['SAL'])
f3(emp['SAL'])
Out[82]:
0 B
1 B
2 B
3 B
4 B
5 B
6 B
7 A
8 A
9 B
10 B
11 B
12 A
13 B
dtype: object
ex) 두 객체의 동시 fetch map 적용
# 10번 부서원은 10% 증가, 그 외 부서는 20% 증가한 새로운 급여 출력하기
f_newsal = lambda sal, deptno : round(sal * 1.1) if deptno == 10 else round(sal * 1.2)
f_newsal(5000, 30) # 가능
f_newsal(5000, 30) # 가능
Out[92]: 6000
f_newsal(emp['SAL'], emp['DEPTNO']) # 불가
f_newsal(emp['SAL'], emp['DEPTNO']) # 불가
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_23264\1324258367.py in ?()
----> 1 f_newsal(emp['SAL'], emp['DEPTNO']) # 불가
~\AppData\Local\Temp\ipykernel_23264\3116933835.py in ?(sal, deptno)
----> 1 f_newsal = lambda sal, deptno : round(sal * 1.1) if deptno == 10 else round(sal * 1.2)
~\anaconda3\Lib\site-packages\pandas\core\generic.py in ?(self)
1578 @final
1579 def __nonzero__(self) -> NoReturn:
-> 1580 raise ValueError(
1581 f"The truth value of a {type(self).__name__} is ambiguous. "
1582 "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
1583 )
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
pd.Series(map(f_newsal, emp['SAL'], emp['DEPTNO']))
pd.Series(map(f_newsal, emp['SAL'], emp['DEPTNO']))
Out[95]:
0 960
1 1920
2 1500
3 3570
4 1500
5 3420
6 2695
7 3600
8 5500
9 1800
10 1320
11 1140
12 3600
13 1430
dtype: int64
# ** 참고 : in R)
sapply(v1, f1) # map 매서드
mapply(f1, v1, v2) # map 함수
-03 리스트 내포표현식 (List Comprehension)
리스트는 반복이 어려운 객체이다.
(담아서 표현하는 용도에 가까운 자료구조이므로 반복, 연산에 적합하지 않음)
그러나 리스트의 반복을 수행해야 하는 경우 리스트 내포표현식을 사용한다.
* 사용법)
[ for i in 대상 ]
result = []
for i in li :
...
li = [1,2,3,4,5]
li + 1 # 불가
li + 1
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[97], line 1
----> 1 li + 1
TypeError: can only concatenate list (not "int") to list
# 방법1) for문
result = []
for i in li :
result.append(i + 1)
result
Out[99]: [2, 3, 4, 5, 6]
# 방법2) 리스트 내포표현식
[i + 1 for i in li]
[i + 1 for i in li]
Out[102]: [2, 3, 4, 5, 6]
ex) 이메일 아이디 추출
email = ['abc@naver.com', 'a1004@gmail.com', 'p111@hanmail.net']
# 방법1) for문
result = []
for i in email :
result.append(i.split('@')[0])
result
Out[106]: ['abc', 'a1004', 'p111']
# 방법2) 리스트 내포표현식
[i.split('@')[0] for i in email]
[i.split('@')[0] for i in email]
Out[107]: ['abc', 'a1004', 'p111']
02 groupby
-01 groupby 연산
pandas에서 제공하는 매서드로 dataframe에 적용한다.
emp.groupby(by, # 그룹핑 컬럼
axis, # 방향 (0 : 세로방향, 1 : 가로방향)
level, # 그룹핑할 레벨번호 또는 이름
as_index = True, # 그룹핑컬럼 index 출력 여부
sort = True, # 정렬여부
group_keys = True,
dropna = True) # NA 제외 여부
ex) DEPTNO 별 급여 총합
emp.groupby('DEPTNO')['SAL'].sum()
emp.groupby('DEPTNO')['SAL'].sum()
Out[114]:
DEPTNO
10 8750
20 10875
30 9400
Name: SAL, dtype: int64
emp.groupby('DEPTNO', as_index = False)['SAL'].sum()
emp.groupby('DEPTNO', as_index = False)['SAL'].sum()
Out[115]:
DEPTNO SAL
0 10 8750
1 20 10875
2 30 9400
ex) DEPTNO 별 SAL, COMM 총합
emp.groupby('DEPTNO')[['SAL', 'COMM']].sum()
emp.groupby('DEPTNO')[['SAL', 'COMM']].sum()
Out[119]:
SAL COMM
DEPTNO
10 8750 0.0
20 10875 0.0
30 9400 2200.0
ex) DEPTNO, JOB 별 SAL 평균
emp.groupby(['DEPTNO', 'JOB'])['SAL'].mean()
emp.groupby(['DEPTNO', 'JOB'])['SAL'].mean()
Out[118]:
DEPTNO JOB
10 CLERK 1300.0
MANAGER 2450.0
PRESIDENT 5000.0
20 ANALYST 3000.0
CLERK 950.0
MANAGER 2975.0
30 CLERK 950.0
MANAGER 2850.0
SALESMAN 1400.0
Name: SAL, dtype: float64
-02 외부 객체를 사용한 그룹핑
df = pd.DataFrame([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]], columns = list('ABCD'))
groups = ['g1', 'g1', 'g2', 'g2']
df
Out[129]:
A B C D
0 1 2 3 4
1 5 6 7 8
2 9 10 11 12
3 13 14 15 16
# groups는 객체이므로 ' '로 묶지 않는다.
df.groupby(groups).sum()
df.groupby(groups).sum()
Out[130]:
A B C D
g1 6 8 10 12
g2 22 24 26 28
df.groupby(groups, axis = 1).sum()
df.groupby(groups, axis = 1).sum()
C:\Users\-\ipykernel_23264\3099643746.py:1: FutureWarning: DataFrame.groupby with axis=1 is deprecated. Do `frame.T.groupby(...)` without axis instead.
df.groupby(groups, axis = 1).sum()
Out[131]:
g1 g2
0 3 7
1 11 15
2 19 23
3 27 31
+) 행렬전치
df.T
df.T
Out[132]:
0 1 2 3
A 1 5 9 13
B 2 6 10 14
C 3 7 11 15
D 4 8 12 16
df.T.groupby(groups).sum()
df.T.groupby(groups).sum()
Out[133]:
0 1 2 3
g1 3 11 19 27
g2 7 15 23 31
예제) 아래 데이터에 대해 모든 연도의 상/하반기 실업율 평균 출력
df = pd.read_csv('2000-2013년_연령별실업율_40-49세.csv', encoding = 'cp949')
groups = ['상반기']*6 + ['하반기']*6
df.iloc[:,1:].groupby(groups).mean()
df.iloc[:,1:].groupby(groups).mean()
Out[158]:
2000년 2001년 2002년 ... 2011년 2012년 2013년
상반기 3.783333 3.55 2.216667 ... 2.316667 2.216667 2.133333
하반기 3.216667 2.45 1.783333 ... 1.966667 1.883333 1.816667
[2 rows x 14 columns]
-03 기타 매서드
1) agg
여러 연산함수를 전달 시 사용한다.
emp.groupby('DEPTNO')['SAL'].agg(['max','min','sum','mean'])
emp.groupby('DEPTNO')['SAL'].agg(['max','min','sum','mean'])
Out[159]:
max min sum mean
DEPTNO
10 5000 1300 8750 2916.666667
20 3000 800 10875 2175.000000
30 2850 950 9400 1566.666667
2) apply
각 그룹별 사용자 정의 함수의 적용을 위해 사용한다.
(그룹별 분리 - 함수적용 - 결합 결과 리턴)
emp.head() # 기본 : 위 5개 출력
emp.head(1) # 개수 조절 가능
emp.head() # 기본 : 위 5개 출력
Out[160]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
1 7499 ALLEN SALESMAN 7698.0 1981-02-20 0:00 1600 300.0 30
2 7521 WARD SALESMAN 7698.0 1982-02-22 0:00 1250 500.0 30
3 7566 JONES MANAGER 7839.0 1981-04-02 0:00 2975 NaN 20
4 7654 MARTIN SALESMAN 7698.0 1981-09-28 0:00 1250 1400.0 30
emp.head(1) # 개수 조절 가능
Out[161]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
# 각 그룹별로 1행씩만 출력
emp.groupby('DEPTNO').apply(lambda x : x.head(1))
emp.groupby('DEPTNO').apply(lambda x : x.head(1))
C:\Users\-\2256954100.py:1: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
emp.groupby('DEPTNO').apply(lambda x : x.head(1))
Out[162]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
DEPTNO
10 6 7782 CLARK MANAGER 7839.0 1981-06-09 0:00 2450 NaN 10
20 0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
30 1 7499 ALLEN SALESMAN 7698.0 1981-02-20 0:00 1600 300.0 30
키가 DEPTNO임에도 불구하고 그룹키와 열이 동시에 출력되는 문제가 존재한다.
따라서 DEPTNO 컬럼이 index와 본문 모두에 출력되는 문제를 방지하고 싶다면 group_keys = False 옵션을 사용해야한다.
+) 업데이트를 통해 해당 문제가 자동으로 해결될 예정이라는 메시지가 함께 출력됨을 확인할 수 있다.
emp.groupby('DEPTNO',group_keys = False).apply(lambda x : x.head(1))
emp.groupby('DEPTNO',group_keys = False).apply(lambda x : x.head(1))
C:\Users\-\4115926463.py:1: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
emp.groupby('DEPTNO',group_keys = False).apply(lambda x : x.head(1))
Out[163]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
6 7782 CLARK MANAGER 7839.0 1981-06-09 0:00 2450 NaN 10
0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
1 7499 ALLEN SALESMAN 7698.0 1981-02-20 0:00 1600 300.0 30
include_groups = False를 사용하여 본문에서 DEPTNO 컬럼을 제외할 수도 있다.
emp.groupby('DEPTNO').apply(lambda x : x.head(1), include_groups=False)
emp.groupby('DEPTNO').apply(lambda x : x.head(1), include_groups=False)
Out[164]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM
DEPTNO
10 6 7782 CLARK MANAGER 7839.0 1981-06-09 0:00 2450 NaN
20 0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN
30 1 7499 ALLEN SALESMAN 7698.0 1981-02-20 0:00 1600 300.0
3) transform
원래 데이터의 크기를 유지하면서 그룹연산 결과를 가져다 주는 경우에 사용한다. (in R : transform)
ex) 부서별 최대급여
emp.groupby('DEPTNO')['SAL'].max()
emp.groupby('DEPTNO')['SAL'].max()
Out[193]:
DEPTNO
10 5000
20 3000
30 2850
Name: SAL, dtype: int64
emp['MAX_SAL'] = emp.groupby('DEPTNO')['SAL'].transform('max')
# ** 최대 급여자 추출
emp.loc[emp['MAX_SAL'] == emp['SAL'], ['ENAME','SAL','DEPTNO']]
emp.loc[emp['MAX_SAL'] == emp['SAL'], ['ENAME','SAL','DEPTNO']]
Out[195]:
ENAME SAL DEPTNO
5 BLAKE 2850 30
7 SCOTT 3000 20
8 KING 5000 10
12 FORD 3000 20
ex) std에서 성별별로 몸무게가 가장 많이 나가는 학생의 이름, 성별(남자, 여자), 몸무게 출력
std = pd.read_csv('student.csv', encoding = 'cp949')
f1 = lambda x : '남자' if str(x)[6] == '1' else '여자'
std['성별'] = std['JUMIN'].map(f1)
std['MAX_WEIGHT'] = std.groupby('성별')['WEIGHT'].transform('max')
std.loc[std['MAX_WEIGHT'] == std['WEIGHT'], ['NAME', '성별', 'WEIGHT']]
std.loc[std['MAX_WEIGHT'] == std['WEIGHT'], ['NAME', '성별', 'WEIGHT']]
Out[245]:
NAME 성별 WEIGHT
3 김재수 남자 83
8 구유미 여자 58
03 조인 (merge)
pd.merge(left, # 첫번째 대상
right, # 두번째 대상
how, # 조인종류 (inner, left, right, outer, cross)
on, # 조인키 (양쪽 조인키 이름이 같을 때)
left_on, # 첫번째 대상의 조인키 (양쪽 조인키 이름이 다를 때)
right_on, # 두번째 대상의 조인키 (양쪽 조인키 이름이 다를 때)
left_index = False, # index로 조인 시 사용
right_index = False, # index로 조인 시 사용
sort = False, # 정렬
suffixes : ('_x','_y')) # 구분자
ex) emp, dept를 조인하여 각 직원의 이름, 급여, 부서명 출력
emp = pd.read_csv('emp.csv')
dept = pd.read_csv('dept.csv')
pd.merge(emp, dept, on = 'DEPTNO')[['ENAME','SAL','DNAME']]
pd.merge(emp, dept, on = 'DEPTNO')[['ENAME','SAL','DNAME']]
Out[251]:
ENAME SAL DNAME
0 SMITH 800 RESEARCH
1 ALLEN 1600 SALES
2 WARD 1250 SALES
3 JONES 2975 RESEARCH
4 MARTIN 1250 SALES
5 BLAKE 2850 SALES
6 CLARK 2450 ACCOUNTING
7 SCOTT 3000 RESEARCH
8 KING 5000 ACCOUNTING
9 TURNER 1500 SALES
10 ADAMS 1100 RESEARCH
11 JAMES 950 SALES
12 FORD 3000 RESEARCH
13 MILLER 1300 ACCOUNTING
ex) std, exam을 조인하여 각 학생의 이름, 학년, 성적 출력
std = pd.read_csv('student.csv', encoding = 'cp949')
exam = pd.read_csv('exam_01.csv', encoding = 'cp949')
pd.merge(std, exam, on = 'STUDNO')[['NAME','GRADE','TOTAL']]
pd.merge(std, exam, on = 'STUDNO')[['NAME','GRADE','TOTAL']]
Out[256]:
NAME GRADE TOTAL
0 이진욱 4 84
1 서재수 4 78
2 이미경 4 83
3 김재수 4 62
4 박동호 4 88
5 김신영 3 92
6 신은경 3 87
7 오나라 3 81
8 구유미 3 79
9 임세현 3 95
10 일지매 2 89
11 김진욱 2 77
12 안광훈 2 86
13 김문호 2 82
14 노정호 2 87
15 이윤나 1 91
16 안은수 1 88
17 인영민 1 82
18 김주현 1 83
19 허우 1 97
ex) std, pro 조인하여 각 학생의 이름, 학년, 지도교수이름 출력
pro = pd.read_csv('professor.csv', encoding = 'cp949')
pd.merge(std, pro) # NAME, PROFNO로 조인됨
pd.merge(std, pro, on = 'PROFNO') # inner join으로 인해 5개 행 생략 (지도교수가 없는 학생)
pd.merge(std, pro, on = 'PROFNO') # inner join으로 인해 5개 행 생략 (지도교수가 없는 학생)
Out[259]:
STUDNO NAME_x ID_x ... DEPTNO EMAIL HPAGE
0 9411 이진욱 75true ... 101 captain@abc.net http://www.abc.net
1 9412 서재수 pooh94 ... 102 lamb1@hamail.net NaN
2 9413 이미경 angel000 ... 103 naone10@empal.com NaN
3 9414 김재수 gunmandu ... 201 chebin@daum.net NaN
4 9415 박동호 pincle1 ... 202 mypride@hanmail.net NaN
5 9511 김신영 bingo ... 101 sweety@abc.net http://www.abc.net
6 9512 신은경 jjang1 ... 102 number1@naver.com http://num1.naver.com
7 9513 오나라 nara5 ... 202 mypride@hanmail.net NaN
8 9514 구유미 guyume ... 301 silver-her@daum.net NaN
9 9515 임세현 shyun1 ... 201 chebin@daum.net NaN
10 9611 일지매 onejimae ... 101 sweety@abc.net http://www.abc.net
11 9612 김진욱 samjang7 ... 102 lamb1@hamail.net NaN
12 9613 안광훈 nonnon1 ... 201 gogogo@def.com NaN
13 9614 김문호 munho ... 202 mypride@hanmail.net NaN
14 9615 노정호 star123 ... 301 silver-her@daum.net NaN
[15 rows x 21 columns]
pd.merge(std, pro, on = 'PROFNO', how = 'left') # left outer join으로 인해 생략된 5개 행 출력 (지도교수가 없는 학생)
pro = pd.read_csv('professor.csv', encoding = 'cp949')
pd.merge(std, pro, on = 'PROFNO', how = 'left')
Out[258]:
STUDNO NAME_x ... EMAIL HPAGE
0 9411 이진욱 ... captain@abc.net http://www.abc.net
1 9412 서재수 ... lamb1@hamail.net NaN
2 9413 이미경 ... naone10@empal.com NaN
3 9414 김재수 ... chebin@daum.net NaN
4 9415 박동호 ... mypride@hanmail.net NaN
5 9511 김신영 ... sweety@abc.net http://www.abc.net
6 9512 신은경 ... number1@naver.com http://num1.naver.com
7 9513 오나라 ... mypride@hanmail.net NaN
8 9514 구유미 ... silver-her@daum.net NaN
9 9515 임세현 ... chebin@daum.net NaN
10 9611 일지매 ... sweety@abc.net http://www.abc.net
11 9612 김진욱 ... lamb1@hamail.net NaN
12 9613 안광훈 ... gogogo@def.com NaN
13 9614 김문호 ... mypride@hanmail.net NaN
14 9615 노정호 ... silver-her@daum.net NaN
15 9711 이윤나 ... NaN NaN
16 9712 안은수 ... NaN NaN
17 9713 인영민 ... NaN NaN
18 9714 김주현 ... NaN NaN
19 9715 허우 ... NaN NaN
[20 rows x 21 columns]
[ 연습 문제 ]
1. 부서별 최대 급여자의 이름, 부서번호, 급여를 출력 (groupby + merge)
1) 부서별 최대 급여 확인
emp_maxsal = emp.groupby('DEPTNO', as_index = False)['SAL'].max()
pd.merge(emp, emp_maxsal)
pd.merge(emp, emp_maxsal)
Out[265]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
0 7698 BLAKE MANAGER 7839.0 1981-05-01 0:00 2850 NaN 30
1 7788 SCOTT ANALYST 7566.0 1987-04-17 0:00 3000 NaN 20
2 7839 KING PRESIDENT NaN 1981-11-17 0:00 5000 NaN 10
3 7902 FORD ANALYST 7566.0 1981-12-03 0:00 3000 NaN 20
# in spl)
select
from emp e, (select deptno, max(sal) as max_sal
from
group by deptno) i
where e.deptno = i.deptno
and e.sal = i.max_sal;
2) std에서 학년별 성적이 가장 높은 학생의 이름, 학년, 성적 출력
df1 = pd.merge(std, exam, on = 'STUDNO')
bestscore = df1.groupby('GRADE', as_index = False)['TOTAL'].max()
pd.merge(df1, bestscore)[['NAME','GRADE','TOTAL']]
# 문제풀이
std2 = pd.merge(std, exam)[['NAME', 'GRADE', 'TOTAL']]
std_maxtotal = std2.groupby('GRADE', as_index = False)['TOTAL'].max()
pd.merge(std2, std_maxtotal)
pd.merge(df1, bestscore)[['NAME','GRADE','TOTAL']]
Out[327]:
NAME GRADE TOTAL
0 박동호 4 88
1 임세현 3 95
2 일지매 2 89
3 허우 1 97
3) std에서 학년별 평균 성적보다 성적이 낮은 학생의 이름, 학년 성적 출력 (non equi join)
std2['AVG_TOTAL'] = std2.groupby('GRADE', as_index = False)['TOTAL'].transform('mean')
std2.loc[std2['TOTAL'] < std2['AVG_TOTAL'], :]
std2.loc[std2['TOTAL'] < std2['AVG_TOTAL'], :]
Out[330]:
NAME GRADE TOTAL AVG_TOTAL
1 서재수 4 78 79.0
3 김재수 4 62 79.0
7 오나라 3 81 86.8
8 구유미 3 79 86.8
11 김진욱 2 77 84.2
13 김문호 2 82 84.2
16 안은수 1 88 88.2
17 인영민 1 82 88.2
18 김주현 1 83 88.2
[ 연습 문제 - non equi join ]
# gogak, gift 사용해서 각 고객의 포인트 기준 받을 수 있는 상품의 이름을 하나씩 출력하기
gogak = pd.read_csv('gogak.csv', encoding = 'cp949')
gift = pd.read_csv('gift.csv', encoding = 'cp949')
gift.loc[(gogak['POINT'][0] > gift['G_START']) & (gogak['POINT'][0] < gift['G_END']), 'GNAME'].iloc[0]
f_gift = lambda x : gift.loc[(x > gift['G_START']) & (x < gift['G_END']), 'GNAME'].iloc[0]
gogak['POINT'].map(f_gift)
gogak['POINT'].map(f_gift)
Out[350]:
0 양쪽문냉장고
1 참치세트
2 주방용품세트
3 참치세트
4 샴푸세트
5 샴푸세트
6 세차용품세트
7 주방용품세트
8 LCD모니터
9 세차용품세트
10 샴푸세트
11 참치세트
12 산악용자전거
13 세차용품세트
14 산악용자전거
15 LCD모니터
16 노트북
17 노트북
18 벽걸이TV
19 벽걸이TV
Name: POINT, dtype: object'아이티윌_데이터 분석 55기 > 강의내용 필기_Python' 카테고리의 다른 글
| #6 6일차_pd의 행·열 결합 / 수학 및 통계 함수·메서드 / 결측치 처리 (0) | 2026.05.18 |
|---|---|
| #5 5일차_형 변환 함수/매서드, SQL사용, DB 연동, array (0) | 2026.05.15 |
| #3 3일차_조건문, 반복문 (0) | 2026.05.13 |
| #2 2일차_문자열 매서드, pandas 자료구조(Series, DataFrame), 적용함수 (0) | 2026.05.12 |
| #1 1일차_파이썬 설치 및 실행, 실습, 자료구조(리스트) (0) | 2026.05.11 |