Language/Python

231120 Python_equi join, map(), 타입 변경, 그룹함수, aggregate, merge(join), right_on(left_on),right_index(left_index)=True, how='inner/left/right/outer'

잇꼬 2023. 11. 20. 20:26
728x90
반응형
SMALL

# 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})
728x90
반응형
LIST