# equi join
emp.loc[(emp['COMMISSION_PCT'].notnull())&(emp['DEPARTMENT_ID'].isnull()),['EMPLOYEE_ID', 'COMMISSION_PCT']]
# 함수 생성
def square(arg):
return arg**2
square(10)
lst = [1,2,3]
square[1,2,3] #오류발생
square(lst[0])
square(lst[1])
square(lst[2])
[square(i) for i in lst] # 반복문 활용
map(함수명, 변수명) 메소드
#1. 속도 빠름
#2. 대량의 데이터시 사용
map(square, lst)
list(map(square, lst))
list(map(lambda arg:arg**2, lst))
# Series , 인덱싱할 이유X
s = Series([1,2,3])
square(s)
map(square, s)
list(map(square, s))
Series(map(lambda arg:arg**2, s))
# 적용시키기
s.apply(square)
s.apply(lambda arg:arg**2)
# DataFrame 생성
df = DataFrame([[1,2,3], [4,5,6]])
df.apply(square)
square(df) # 바로 적용해도 문제없이 무방하다
df.apply(lambda arg:arg**2)
emp['SALARY']*12 + emp['COMMISSION_PCT'].fillna(0)
Series(1).isnull() # Series 타입
Series(1).isnull().bool()
type(Series(1).isnull()) # Series
type(Series(1).isnull().bool())
# Series의 isnull() 메소드 이라 스칼라타입 변수는 적용X
# 해결) 타입변경(Series 타입 -> 스칼라 타입)
def nvl(arg): # 스칼라타입 변수
if Series(arg).isnull().bool(): # bool 자료형
return 0
else:
return arg
emp['SALARY']*12 + emp['COMMISSION_PCT'].apply(nvl)
# pandas -> isnull
pd.isnull(1)
type(pd.isnull(1))
# pandas isnull() : 스칼라타입 isnull()
def nvl(arg): # 스칼라타입 변수
if pd.isnull(arg):
return 0
else:
return arg
emp['SALARY']*12 + emp['COMMISSION_PCT'].apply(nvl)
# 첫글자가 대문자 'E'인 글자
emp['LAST_NAME']
'Smith'.startswith('S')
emp['LAST_NAME'].startswith('S') # 오류발생
# 해결1) 인덱싱
emp['LAST_NAME'][0].startswith('S')
emp['LAST_NAME'][1].startswith('S')
# 해결2) apply() + lambda 활용
emp[emp['LAST_NAME'].apply(lambda arg:arg.startswith('S'))]
emp[emp['LAST_NAME'].apply(lambda arg:arg[0] == 'S')]
# 해결3) Series 에서 활용 가능
emp['LAST_NAME'].str.startswith('S')
emp[emp['LAST_NAME'].str.startswith('S')]
<<연습>>
s = Series([' big', 'data ', ' big data '])
s
len('data')
s.apply(lambda arg: len(arg))
# apply() 대신 활용.
# 변수명.타입명.함수명
# 문자 길이
s.str.len()
# 문자의 앞과 뒤 공백제거
s.str.strip()
s.str.strip().str.len()
# 문자의 앞 공백제거
s.str.lstrip()
s.str.lstrip().str.len()
# 문자의 뒤 공백제거
s.str.rstrip()
s.str.rstrip().str.len()
# 문자의 대,소문자로 변경
s.str.lower()
s.str.upper()
# 문장의 첫글자 대문자, 뒷글자 소문자 변경
s.str.capitalize() # 공백이 있기때문에 적용X
s.str.strip().str.capitalize()
# 단어별 첫글자 대문자, 뒷글자 소문자 변화
s.str.title()
# 소문자대문자, 대문자는 소문자로 변환
s.str.swapcase()
# 문자를 치환하는 함수 (미리보기)
s.str.replace('big', 'BIG')
# 문자를 찾아서 위치를 반환하는 함수
s.str.find('a') # 없으면 -1
s.str.find('a', 0)
s.str.find('a', 2)
s.str.find('a', 2).values # array 으로 확인
# 문자를 찾아서 위치를 반환하는 함수, 없으면 오류발생
s.str.index('a')
# findall : 문자열을 찾아서 그 문자열을 반환하는 함수
s.str.find('a') # 위치반환
s.str.findall('a') # 해당 문자열 반환
# 문자열로 시작되는지 체크하는 함수
s.str.startswith('b')
# 문자열로 끝나는지 체크하는 함수
s.str.endswith('a')
# 특정한 문자열 포함여부 체크하는 함수
s.str.contains('a')
# 대소문자 구분
s1 = s.str.replace('a', 'A')
s1.str.contains('a')
s1.str.contains('A')
# case=True/False
s1.str.contains('a', case=True) # case=True 대소문자 구분(기본값)
s1.str.contains('A', case=False) # case=False 대소문자 구분하지 않고 찾기
# 두 번째 위치에 'i' 문자 찾기
# 지정된 위치(인덱스)의 값을 반환하는 함수
# SQL : substr()
emp['LAST_NAME'].str.get(0) # 첫 번째 문자
emp['LAST_NAME'].str.get(1) == 'i' # 두 번째 문자
emp[emp['LAST_NAME'].str.get(1) == 'i']['LAST_NAME']
emp[emp['LAST_NAME'].str.get(2).isin(['a', 'e'])]['LAST_NAME'] # 세 번째 위치
# 지정된 인덱스 사이값을 반환하는 함수
# stop=숫자 : 숫자 전까지 출력
emp['LAST_NAME'].str.slice(start=0, stop=2)
emp['LAST_NAME'].str.slice(start=2, stop=3)
emp[emp['LAST_NAME'].str.slice(start=2, stop=3).isin(['a', 'e'])]['LAST_NAME']
obj = Series(['big', 'big data'])
obj.str.title()
"B"+obj.str.slice(start=1)
# 인덱스 사이값을 다른값으로 수정하는 함수
# 인덱스 값 기준으로 수정
obj.str.slice_replace(start=0, stop=1, repl="B")
# 지정된 길이 패딩, 20자리 고정, 왼쪽으로 문자 고정
# SQL : rpad, lpad
obj.str.pad(width=20, side='left', fillchar='_')
obj.str.pad(width=20, side='right', fillchar='_')
# 길이 20글자 고정, 공백자리는 '_' 로 채움
obj.str.center(width=20, fillchar='_')
obj.str.ljust(width=20, fillchar='_')
obj.str.rjust(width=20, fillchar='_')
obj.str.rjust(width=20, fillchar='0')
obj.str.zfill(width=20) # obj.str.rjust(width=20, fillchar='0') 와 동일한 값
# 숫자형에서는 오류
emp['SALARY'].str.zfill(width=15)
# 문자형에서는 가능
emp['LAST_NAME'].str.zfill(width=15)
# Series 생성
obj = Series(['itwill@itwill.com', 'itwill'])
# split() : 문자를 기준으로 분리하는 함수
obj.str.split('@')
obj.str.split('@', expand=True) # 열로 출력
obj.str.split('@', expand=True)[0]
obj.str.split('@', expand=True)[1]
# partition : 문자를 기준으로 분리하되, 문자도 같이 출력
obj.str.partition('@')
obj.str.rpartition('@') # 없으면 공백으로 출력
obj = Series(['1/7', '7', 'seven', 'SEVEN', 'Seven', 'seven7', '칠', '칠 7', ' ', '7#'])
obj
# 순수하게 한글, 알파벳, 숫자로만 구성 여부를 체크하는 함수
obj.str.isalnum()
obj[obj.str.isalnum()]
# 순수하게 알파벳로만 구성 여부를 체크하는 함수
obj[obj.str.isalpha()]
# 순수하게 숫자로만 구성 여부를 체크하는 함수
obj[obj.str.isdigit()]
obj[obj.str.isnumeric()]
# 순수하게 알파벳 소문자로만 구성 여부를 체크하는 함수
obj[obj.str.islower()]
# 순수하게 알파벳 대문자로만 구성 여부를 체크하는 함수
obj[obj.str.isupper()]
# 순수하게 첫글자 대문자+뒷글자 소문자로만 구성 여부를 체크하는 함수
obj[obj.str.istitle()]
# 순수하게 공백으로만 구성 여부를 체크하는 함수
obj[obj.str.isspace()]
■ 그룹함수
obj = Series([2,3,4,5,6,None,100])
obj.sum()
obj.sum(skipna=True) # NaN 은 먼저 제거한 후 계한
obj.sum(skipna=False)
obj.mean() # 평균값
obj.median() # 중앙값
obj.var() # 분산, 편차제곱
obj.std() # 표준편차
obj.max()
obj.min()
obj.idxmax() # 최대값의 인덱스
obj[obj.idxmax()]
obj.idxmin() # 최소값의 인덱스
obj[obj.idxmin()]
obj.argmin() # 최소값의 인덱스
obj[obj.argmin()]
obj.argmax() # 최대값의 인덱스
obj[obj.argmax()]
obj = Series([1,2,3,100,4,5,6,None,100])
obj.max()
obj.idxmax()
obj.argmax()
# 최대값이 있는 위치
obj[obj == obj.max()].index
obj.cumsum() # 누적합
obj.cumprod() # 누적곱
obj = Series([80,10,2,3,100,4,5,1,None,100])
obj.cummin() # 누적최소값
obj.cummax() # 누적최대값
obj.count() # NaN 제외한 건수
len(obj) # NaN 포함한 건수
df = DataFrame(data=[[60,80,70],[100,80,90],[60,90,50]],
index=['홍길동','박찬호','손흥민'],
columns=['영어', '수학', '국어'])
df
df.sum() # 열의 합, 기본값
df.sum(axis=0)
df.sum(axis="rows")
df.sum(axis=1) # 행의 합, 총점
df.sum(axis="columns")
# df 추가
df.loc['제임스', '영어'] = 100
df.loc['제임스', '수학'] = None
df.loc['제임스', '국어'] = 90
df
# sum()
df.sum()
df.sum(axis=0, skipna=True) # 열의합, 기본값
df.sum(axis=0, skipna=False)
df.sum(axis=1, skipna=True) # 행의합
df.sum(axis=1, skipna=False)
# 특정한 열의 합
df['영어'].sum()
# 같은 값, SQL/Python 코드, sum()
SELECT sum(SALARY) FROM emp;
emp['SALARY'].sum()
# 같은 값, SQL/Python 코드, group by절
SELECT DEPARTMENT_ID, sum(SALARY) FROM emp GROUP BY DEPARTMENT_ID;
emp['SALARY'].groupby(emp['DEPARTMENT_ID']).sum()
emp.groupby('DEPARTMENT_ID')['SALARY'].sum()
emp.groupby('DEPARTMENT_ID')['SALARY'].mean()
emp.groupby('DEPARTMENT_ID')['SALARY'].median()
emp.groupby('DEPARTMENT_ID')['SALARY'].var()
emp.groupby('DEPARTMENT_ID')['SALARY'].std()
emp.groupby('DEPARTMENT_ID')['SALARY'].max()
emp.groupby('DEPARTMENT_ID')['SALARY'].min()
SELECT DEPARTMENT_ID, sum(SALARY), avg(SALARY), max(SALARY), min(SALARY)
FROM emp
GROUP BY DEPARTMENT_ID;
# aggregate : 그룹함수 list 함수
emp['SALARY'].groupby(emp['DEPARTMENT_ID']).aggregate(['sum', 'mean', 'max', 'min'])
emp.groupby('DEPARTMENT_ID')['SALARY'].aggregate(['sum', 'mean', 'max', 'min'])
# 같은 값, SQL/Python 코드
# 그룹함수 컬럼이 다를경우
SELECT DEPARTMENT_ID, sum(SALARY), max(HIRE_DATE), min(HIRE_DATE)
FROM emp
GROUP BY DEPARTMENT_ID;
emp.groupby('DEPARTMENT_ID').aggregate({'SALARY':'sum', 'HIRE_DATE':['max', 'min']})
# DEPARTMENT_ID 결측값을 다른 값으로 수정한 후 수행
emp.DEPARTMENT_ID = emp.DEPARTMENT_ID.fillna(999)
emp['SALARY'].groupby(emp['DEPARTMENT_ID']).sum()
# employees 테이블 다시 블러오기
emp = pd.read_csv('c:/data/employees.csv')
# SQL, Python 코드
SELECT DEPARTMENT_ID, JOB_ID, sum(SALARY)
FROM emp
GROUP BY DEPARTMETN_ID, JOB_ID;
emp['SALARY'].groupby([emp['DEPARTMENT_ID'],emp['JOB_ID']]).sum()
x = emp['SALARY'].groupby([emp['DEPARTMENT_ID'].fillna(999),emp['JOB_ID']]).sum()
type(x)
x # 다중인덱스
x.index
y = x.reset_index() # DataFrame
type(y)
y.set_index('DEPARTMENT_ID') # 미리보기
y.set_index(['DEPARTMENT_ID', 'JOB_ID'])
y
# SQL : pivot
x.unstack()
x.unstack().fillna(0)
# for문 을 활용
for name, group in emp.groupby('DEPARTMENT_ID'):
print(name)
print(group)
for name, group in emp.groupby('DEPARTMENT_ID')['LAST_NAME']:
print(name)
print(group)
for name, group in emp.groupby('DEPARTMENT_ID')[['LAST_NAME', 'SALARY']]:
print(name)
print(group)
# 오류발생, DEPARTMENT_ID 가 존재하지 않아서
for name, group in emp[['LAST_NAME', 'SALARY', 'DEPARTMENT_ID']].groupby('DEPARTMENT_ID'):
print(name)
print(group)
# 생성
dept = pd.read_csv('c:/data/dept.csv')
dept.info()
emp.info()
■ merge(SQL : join)
#1. SQL 에서는 JOIN과 동일하다.
#2. 서로 다른 데이터 프레임의 특정한 열의 기준으로 연결하는 방법
# SQL : EQUI JOIN , INNER JOIN, SIMPLE JOIN, 등가조인
SELECT emp.last_name, dept.department_name
FROM emp, dept
WHERE emp.department_id = dept.department_id;
SELECT emp.last_name, dept.department_name
FROM emp JOIN dept
ON emp.department_id = dept.department_id;
SELECT emp.last_name, dept.department_name
FROM emp NATURAL JOIN dept;
SELECT emp.last_name, dept.department_name
FROM emp JOIN dept
USING(department_id);
# natural join : 양쪽 데이터프레임의 동일한 이름의 모든 컬럼을 조인조건 술어를 수행한다
SELECT emp.last_name, dept.department_name FROM emp NATURAL JOIN dept;
pd.merge(emp, dept)
pd.merge(emp, dept, how='inner') # 기본값
# JOIN USING : 기준 컬럼을 지정해서 조인조건 술어를 수행한다.
SELECT emp.last_name, dept.department_name
FROM emp JOIN dept
USING(department_id);
pd.merge(emp,dept, on='DEPARTMENT_ID')
★ JOIN ON : 조인조건술어를 직접 명시한다. , 이 문장을 잘 기억해주자!
SELECT emp.last_name, dept.department_name
FROM emp JOIN dept
ON emp.department_id = dept.department_id;
pd.merge(emp, dept, left_on = 'DEPARTMENT_ID', right_on='DEPARTMENT_ID')
x = pd.merge(emp, dept, left_on = 'DEPARTMENT_ID', right_on='DEPARTMENT_ID', how='inner')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
# SQL : OUTER JOIN
# 키 값이 불일치되는 데이터를 출력하는 조인
#1. LEFT OUTER JOIN
SELECT emp.last_name, dept.department_name
FROM emp, dept
WHERE emp.department_id = dept.department_id(+);
SELECT emp.last_name, dept.department_name
FROM emp LEFT OUTER JOIN dept
ON emp.department_id = dept.department_id;
x = pd.merge(emp, dept, left_on = 'DEPARTMENT_ID', right_on='DEPARTMENT_ID', how='left')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
#2. RIGHT OUTER JOIN
SELECT emp.last_name, dept.department_name
FROM emp, dept
WHERE emp.department_id(+) = dept.department_id;
SELECT emp.last_name, dept.department_name
FROM emp RIGHT OUTER JOIN dept
ON emp.department_id = dept.department_id;
x = pd.merge(emp, dept, left_on = 'DEPARTMENT_ID', right_on='DEPARTMENT_ID', how='right')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
#3. FULL OUTER JOIN
SELECT emp.last_name, dept.department_name
FROM emp, dept
WHERE emp.department_id(+) = dept.department_id;
UNION
SELECT emp.last_name, dept.department_name
FROM emp, dept
WHERE emp.department_id = dept.department_id(+);
SELECT emp.last_name, dept.department_name
FROM emp FULL OUTER JOIN dept
ON emp.department_id = dept.department_id;
x = pd.merge(emp, dept, left_on = 'DEPARTMENT_ID', right_on='DEPARTMENT_ID', how='outer')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
dept.info()
dept.set_index('DEPARTMENT_ID') # 미리보기
# dept = dept.set_index('DEPARTMENT_ID')
# inplace=True : 데이터프레임 바로적용
dept.set_index('DEPARTMENT_ID', inplace=True) # 즉시적용
dept.info()
dept.index
# dept의 DEPARMENT_ID 가 index 로 되어 있다면, 'right_index=True' 로 변경
# emp의 DEPARTMENT_ID : 조인조건 술어
x = pd.merge(emp, dept, left_on = 'DEPARTMENT_ID', right_index=True , how='inner')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
# DEPARMENT_ID 가 index 로 되어 있다면, 'right_index=True' 로 변경
emp.set_index('DEPARTMENT_ID', inplace=True)
emp.info()
emp.index
x = pd.merge(emp, dept, left_index=True, right_index=True , how='inner')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
# outer join : left, right, full
x = pd.merge(emp, dept, left_index=True, right_index=True , how='left')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
x = pd.merge(emp, dept, left_index=True, right_index=True , how='right')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
x = pd.merge(emp, dept, left_index=True, right_index=True , how='outer')
x[['LAST_NAME', 'DEPARTMENT_NAME']]
emp.info()
emp.index
emp.reset_index() # 미리보기
emp.reset_index(inplace=True) # 바로 적용
emp
dept.reset_index(inplace=True)
dept
# 테이블 불러오기
loc = pd.read_csv('c:/data/loc.csv')
job = pd.read_csv('c:/data/job.csv')
emp.info()
dept.info()
loc.info()
job.info()
# JOIN 은 최대 2개이니, 변수처리해서 한번더 JOIN 한다
x = pd.merge(dept, loc, on='LOCATION_ID')
x.info()
pd.merge(x, emp, on = 'DEPARTMENT_ID')
pd.merge(x, emp, on = 'DEPARTMENT_ID', how='right')[['EMPLOYEE_ID', 'DEPARTMENT_ID', 'CITY']]
# self join
SELECT w.EMPLOYEE_ID, w.LAST_NAME, m.LAST_NAME
FROM emp w, emp m
WEHRE w.MANAGER_ID = m.EMPLOYEE_ID;
# x, y
pd.merge(emp, emp, left_on='MANAGER_ID', right_on='EMPLOYEE_ID')[['LAST_NAME_x', 'LAST_NAME_y']]
pd.merge(emp, emp, left_on='MANAGER_ID', right_on='EMPLOYEE_ID', how='left')[['LAST_NAME_x', 'LAST_NAME_y']]
# non equi join, 비등가조인, pandas: 문법제공X
SELECT e.employee_id, e.salary, j.grade_level
FROM emp e, job j
WHERE e.salary >= j.lowest_sal AND e.salary <= j.highest_sal;
job.info()
job
# WHERE e.salary >= j.lowest_sal AND e.salary <= j.highest_sal;
job[(20000 >= job.LOWEST_SAL)&(20000 <= job.HIGHEST_SAL)]['GRADE_LEVEL']
job[(10000 >= job.LOWEST_SAL)&(10000 <= job.HIGHEST_SAL)]['GRADE_LEVEL']
# values 값
job[(10000 >= job.LOWEST_SAL)&(10000 <= job.HIGHEST_SAL)]['GRADE_LEVEL'].values[0]
# 각각의 사원들 등급 출력
# apply(lambda) 활용 : 반복
emp['SALARY'].apply(lambda arg:job[(arg >= job.LOWEST_SAL)&(arg <= job.HIGHEST_SAL)]['GRADE_LEVEL'].values[0])
DataFrame({'이름':emp['LAST_NAME'],'급여':emp['SALARY']})
grade = emp['SALARY'].apply(lambda arg:job[(arg >= job.LOWEST_SAL)&(arg <= job.HIGHEST_SAL)]['GRADE_LEVEL'].values[0])
grade
DataFrame({'이름':emp['LAST_NAME'], '급여':emp['SALARY'], '급여등급':grade})