Today's Goals
1. SQL 꾸준한 연습
2. 파이썬 익숙해지기 - 파이썬 코드카타, pandas 기초 다지기, 파이썬 개인과제
오늘 추가 발제가 있다는걸 까맣게 잊었다.
드디어 본격적인 파이썬 분석의 지옥으로...
pandas 항상 import 해서 쓰긴 했지만 아직도 뭐가 뭔지 모른다.
그놈의 df는 왜 계속 점을 찍고 다른 함수들이 연달아 나온건지..
이번엔 이녀석을 좀 이해하면 소원이 없겠다.
1. SQL 연습
SQL 코드카타
[CROSS JOIN, 그리고 잊고있던 COUNT(*)의 주의점]
select a.student_id, a.student_name, b.subject_name, count(c.subject_name) as attended_exams
from Students a
cross join Subjects b
left join Examinations c
on a.student_id = c.student_id and b.subject_name=c.subject_name
group by a.student_id, b.subject_name
order by student_id, subject_name
- 학생별 과목별 시험 응시 횟수를 구하는 문제였음
- 테이블은 학생정보, 과목이름, 학생 id와 응시 과목 이렇게 3가지
- 도대체 과목 이름만 담긴 테이블이 왜 필요한지 의문 덩어리
- 최종적으로, 응시 횟수가 0번인 것도 계산되어야 했고, 그렇다면 학생별로 세과목 모든 경우를 확인 할 수 있도록, 학생정보와 과목이름 간의 CROSS JOIN이 필요했기 때문이다!!!!!!!!!!!
- 매일 inner 와 left만 써서 잊고 있던 cross join의 개념을 확인하고 가자
- 두 테이블의 행x행 만큼 행이 생성되고, on을 사용할 필요가 없음
- 따라서 위 쿼리에서 세 테이블을 join 하고 나면 나오는 결과는 아래와 같음
- 여기서 응시 횟수를 count 할 때, count(*)를 하면 안되는 이유, *는 null인 경우까지 모두 세어주는 녀석인걸 잊지 말아야함
2. 파이썬 자신감 회복기
Python 전처리 강의 - Pandas
[Pandas의 자료형, 시리즈와 데이터프레임]
- series는 컬럼 하나, series가 여러개 모여서 dataframe이 되는 것
- 각 컬럼의 값을 줄 세워서, 행별로 그 순서를 정해준 것이 index > 인덱스는 기본적으로 순서대로 숫자가 부여되지만 따로 값을 지정할 수도 있음
[csv 저장과 index]
- csv 저장시, index 설정에 따라 파일을 불러올 때, 인덱스가 하나의 컬럼이 되어있을 수 있음
df.to_csv('./newfile.csv', index = False)
- index = False : 인덱스를 하나의 컬럼으로 저장하지 않음(인덱스 없는 테이블)
- index = True는 기본값, 이 상태로 저장했다면 불러올 때, read_csv(경로, index_col=0) 를 써준다면 인덱스 없이 불러와짐
[float 타입은 int로 변경할 수 있다]
- string에서 int로는 변경할 수 없음(소수점 아래 값이 어디고, 정수가 어딘지 문자열에서는 구분할 수 없음)
- float에서 int로 변경 시, 소수점 아래는 버림되고 기존 값에서 정수 부분만 가져오는 것
[데이터프레임에서 특정 영역을 확인하는 방법, loc & iloc]
- iloc[인덱스값, 컬럼값] : 행번호 열번호로 데이터 선택
- loc[인덱스값, 컬럼값] : 행이름 열이름으로 데이터 선택
- iloc[a:b:c] : a는 시작행 위치, b는 마지막행 위치+1, c는 불러올 간격
- iloc[ : , 컬럼순서] : 행이 아닌 열(컬럼)을 가져오는 것
[데이터프레임에서 컬럼을 불러오는 법 - loc을 쓰지 않아도 된다.]
- df['컬럼1'] : 컬럼1의 값을 확인
- df['컬럼1', '컬럼2'] 는 오.류 > df[['컬럼1', '컬럼2']] 처럼 두번을 묶어줘야 함 > []안에 쓰여진 컬럼 순서대로 데이터프레임도 출력됨
[불리언 인덱싱이란]
- 데이터프레임 안에 조건을 넣어 원하는 조건에 해당하는 경우만 필터링하여 데이터프레임으로 확인하는 것
- df[df['gender'] == 'Male'] : gender 컬럼에서 Male에 해당하는 행만 필터링하여 데이터프레임을 출력함(모든 컬럼이 모두 나오고 gender 컬럼만 출력되지 않음)
- 조건 여러개도 가능 > [(조건) & / | (조건)]
[df.loc도 불리언 인덱싱이 가능하다]
- df.loc[조건, 컬럼1:컬럼3] : 조건에 해당하는 행을 모두 필터링하고, 컬럼1~컬럼3까지만 가져옴
- 위에서 컬럼 범위를 설정하지 않으면 모든 컬럼이 출력됨
[isin()도 불리언 인덱싱]
- df[df[컬럼명].isin([리스트])] : 리스트 안에 있는 값에 해당되는 행을 모두 출력함
[불리언 인덱싱의 가독성을 좋게 하는 방법]
- 불리언 인덱싱의 원리는, 조건에 해당하는 df['gender'] == 'Male'를 출력하면 각 행마다 True, False 값이 반환되고, 이걸 다시 df로 묶어 True인 행만 반환되는 것
condition1 = data['컬럼명1'] < 80
condition2 = data['컬럼명2'] >= 50
condition = condition1 & condition2
data[conditon]
# 또는
df[condition1 & condition2]
- 위와 같이 각 조건을 각각의 변수에 할당하고, 최종적으로 필터링해도 가능
- 변수 하나에 여러 조건을 넣는 것도 가능한데, 이 때, 가독성 향상을 위해 조건 줄바꿈을 잘 활용해야 함
- 파이써는 띄어쓰기, 줄바꿈에 민감하므로 연결되는 코드일 때, \를 꼭 넣어줘야함
condition = (data['컬럼명1'] < 80) \
& (data['컬럼명2'] >= 50)\
& (data['컬럼명3'] >= 10)
data[conditon]
[날짜형으로 변환하기]
- df['컬럼'] = pd.to_datetime( df['컬럼'] )
[데이터 프레임을 합치고 싶다면 concat]
- concat의 기본 활용은 SQL에서 union과 유사함(axis = 0 이 기본값이기 때문)
- pd.concat([df1, df2], axis=1) : 데이터 프레임을 좌우로 합치는 것
- 컬럼이 부족하거나, 행이 부족한 부분이 있다면 null로 채워짐
[join처럼 데이터 프레임을 합치고 싶다면 merge]
- SQL의 join과 유사한 방법
- pd.merge(df1, df2, on='기준컬럼', how = 'join 종류') : how의 기본값은 'inner'이고 outer, left, right 모두 가능
[그룹별 집계가 필요하다면 groupby()]
- df.groupby('컬럼').집계함수()
- df.groupby('컬럼').agg(list) : 컬럼의 그룹별 값을 리스트로 묶어 반환
- 그룹화한 컬럼 자체를 집계하려는 것이 아니라면(평균함수를 쓸건데 그룹화한 컬럼은 문자열인 경우 등) 집계함수를 쓸 때 오류가 남
- df.groupby('기준컬럼')['컬럼명'].집계함수() : 특정 컬럼에 대한 집계값만 보고싶은 경우
- groupby()안에 컬럼은 여러개 들어갈 수 있음
- 집계함수 또한 agg()하고 괄호 안에 여러개 가능('mean','sum' 이런식으로 넣으면 그룹별 평균과 합을 모두 구하는것)
- df.groupby('기준컬럼').agg({'컬럼1' : ['max', 'sum'], '컬럼2' : ['sum'], .... }) : 기준컬럼에 따라 그룹화 하여, 불러오는 컬럼마다 다른 집계함수를 적용하고 싶을 때
[pivot 테이블 만드는 법]
- pivot명 = df.pivot_table(index='행이름으로 쓸 컬럼' , columns = '컬럼명으로 쓸 컬럼' , values = '행-열에 해당하는 값으로 넣을 컬럼', aggfunc = 'sum or.... 집계종류')
- columns에는 여러 컬럼이 리스트로 들어갈 수 있는데, 이는 그룹화와 비슷한 의미임 > 예를 들면 컬럼1에서 값이 a인 것 중 컬럼2에서 x인 경우와 y인 경우가 나누어 표시됨
[정렬하는 법, sort_values]
- df.sort_values(by='컬럼명', ascending = False) : 컬럼을 기준으로 내림차순(False) 정렬, 오름차순(True) 정렬
- df.sort_index(ascending = ) : 인덱스 값을 기준으로 정렬
Python 개인 과제 - 해답 풀이
[이메일 유효성 검사 문제, 끝 문자(접미사) 찾기 - endswith]
#문제4
email_list = [
"example@example.com", # 유효한 이메일
"yangbujang@email.co.kr", # 유효한 이메일
"iamhungry.com", # 틀린 이메일 -> @ 누락
"@da.com", # 틀린 이메일 -> ID 누락
"daislove@isnit", # 틀린 이메일 -> 도메인 잘못됨
]
def check_email(email_list) :
for i in email_list :
if ('@' in i) and ('.com' in i or '.co.kr' in i) and i.index('@') > 0 :
print(f"유효한 이메일입니다: '{i}'")
elif '@' not in i :
print(f"유효하지 않은 이메일입니다: '{i}' 이유: '@가 누락'")
elif i.index('@') == 0 :
print(f"유효하지 않은 이메일입니다: '{i}' 이유: 'ID가 누락'")
elif '.com' not in i and '.co.kr' not in i :
print(f"유효하지 않은 이메일입니다: '{i}' 이유: '적절하지 않은 도메인'")
check_email(email_list)
- 위 문제를 풀면서, 도메인 유효성을 검사할 때, .com이 메일 문자열 안에 있다 해도 그 뒤에 또 다른 문자가 붙으면 유효하지 않은 이메일이 된다는 의문이 있었음( .comabc 같은)
- 풀이 강의에서 처음 들은 내장함수, endswith()
- not i.endswith('.com') and not i.endswith('.co.kr')을 하면 com과 co.kr로 끝나지 않는 메일을 검사할 수 있음
- 번외 : 시작 문자 찾기는 startswith()으로
'데이터 부트캠프 - Today I Learned' 카테고리의 다른 글
[스파르타 내일배움캠프 / 데이터 분석 트랙] TIL(Today I Learned)_4주차_24.12.18 (3) | 2024.12.18 |
---|---|
[스파르타 내일배움캠프 / 데이터 분석 트랙] TIL(Today I Learned)_4주차_24.12.17 (3) | 2024.12.17 |
[스파르타 내일배움캠프 / 데이터 분석 트랙] WIL(Weekly I Learned)_3주차 (1) | 2024.12.15 |
[스파르타 내일배움캠프 / 데이터 분석 트랙] TIL(Today I Learned)_3주차_24.12.13 (0) | 2024.12.15 |
[스파르타 내일배움캠프 / 데이터 분석 트랙] TIL(Today I Learned)_3주차_24.12.12 (2) | 2024.12.12 |