웅진 STARTERS 부트캠프

1주 3일차 TIL 정리

WoodenStella 2023. 2. 8. 18:58

1주 3일차의 주 내용은 파이썬의 Pandas 확장프로그램을 활용한 데이터 탐색방법이라 할 수 있다.

대부분의 내용이 생소했어서 오늘의 내용은 꽤나 많을 전망이다.


2일차에서 작성한 pandas의 데이터프레임과 시리즈부터 다시 한 번 보고 가자.

시리즈: 엑셀시트로 가정했을 때, 열 1개 (1차원 데이터)

데이터프레임: 엑셀시트로 가정했을 때, 시트 (2차원 데이터)


시리즈는 index와 value로 구성돼있다.
- index

# 시리즈의 index 가져오기
s.index
# 시리즈 인덱스 지정하기
s.index = ['name','hieght','footsize']
s

- value

# 시리즈의 value 가져오기
s.values


- 시리즈의 통계값 사용하기: 명령어(mean, min, max, median, std)를 사용해 value의 통계값을 구할 수 있다.

print('평균:',s2.mean())
print('최소값:',s2.min())
print('최대값:',s2.max())
print('중간값:',s2.median())
print('표준편차:',s2.std())

(describe를 활용해 요약통계 또한 볼 수 있다.)

s2.describe()


- 시리즈의 주요 메소드: 정렬, 인덱스 리셋, 교체, 데이터프레임으로의 전환 등이 가능하다.

# s3의 value 중 10을 5로 교체
s3 = s3.replace(10,5)
s3
# s3 정렬 (디폴트는 오름차순 : ascending=True)
s3.sort_values()
# s3.sort_values(ascending=False)
# s3을 데이터프레임으로 만들기
s3.to_frame()
# 시리즈 인덱스 새로 만들기
s.reset_index()



- 컬럼명으로 데이터 추출하기

# 시리즈 형태로 데이터 추출: 데이터프레임명['컬럼']
s_name = df['name']
s_name.head()
# 데이터프레임으로 추출하기: 데이터프레임[['컬럼명','컬럼명']]

# 'name','kor' 컬럼 데이터 추출하기
df_name_kor = df[['name','kor']]
df_name_kor.head(5)

- 추출한 데이터 성질 확인

# 타입(시리즈/데이터프레임)의 확인: type
type(s_name)
# series 의 크기가 어떤가?
# shape
s_name.shape
# 컬럼의 데이터타입 알아보기
df['math'].dtype


s유무를 유의하도록 하자.

# 데이터프레임의 자료형 확인
df.dtypes

- 조건에 따른 데이터 추출 (boolean index)

# kor 점수가 100점인 데이터 불린인덱스
df['kor'] == 100

- 위 값에 "데이터프레임명[ ]" 으로 감싸주면 True인 데이터만 노출.

# kor 점수가 100점인 데이터 추출
df[df['kor'] == 100]

- 논리연산자의 사용: 논리연산자는 '&' , '|' ,'~', '^' 기호를 사용한다. 각 조건을 ()로 감싼다.

# 한 과목이라도 100을 받은 학생 추출
df[ (df.kor == 100) | (df.eng == 100) | (df.math == 100) ]
# kor의 값이 60~90인 학생의 name, kor 추출
df[ (df['kor']>=60) & (df.kor<=90) ] [['name','kor']]

# df['kor'] 혹은 df.kor 사용 여부 딱히 상관 무

다음과 같이 뒤에 중괄호를 추가해 필요데이터만 표시할 수도 있다.

- 조건값 도출 (isin)

# 이름이 Amy, Rose인 데이터 추출
df[df['name'].isin(['Amy','Rose'])]

- null값 여부에 따른 추출(isnull, notnull)

# kor이 null인 데이터 추출
df[df.kor.isnull()]


- 인덱스명을 기준으로 행 데이터 추출: 데이터프레임명.loc['인덱스']

(인덱스 형태로 추출하기)

# 인덱스가 i3인 행 추출하여 s1에 담기
s1 = df.loc['i3']
s1

(데이터프레임 형태로 추출하기)
(하나만 추출)

# 인덱스가 i3인 행을 데이터프레임 형태로 추출하기
df.loc[['i3']]

(여러 개 대상)

# 인덱스가 i1,i3,i5인 행 추출하기
df.loc[['i1','i2','i3']]
# 인덱스 i1,i3,i5의 name, kor
df.loc[['i1','i3','i5'],['name','kor']]

- 인덱스가 아닌 행 번호로 데이터 추출하기 데이터프레임명.iloc[행번호]

# 1,3,5번 행 추출하기
df.iloc[[1,3,5]]

(슬라이싱 또한 가능하다)

# 홀수 행번호의 데이터 추출하기
df.iloc[1::2]

- 맥플롯립 라이브러리를 활용한 그래프 그리기

x = ['a','b','c','d','e']
y = [1,3,2,10,7]
plt.scatter(x,y,label='scatter')      # 산점도
plt.bar(x,y,label='bar')              # 막대그래프 (가로 막대그래프는 barh)
plt.plot(x,y,label='plot')            # 선그래프 

# label: 범례에 label달기

plt.title('Test Graph', size = 15)
plt.xlabel('x')
plt.ylabel('y')

plt.legend()   #범례표시
plt.show()

(다른 예시)

# x축 y축 데이터 준비

x = df['name']
y = df['kor']
plt.bar(x,y)
plt.xticks(rotation=90)     # 하단 이름 글자 회전
plt.title('Scores', size=20)
plt.xlabel('name')
plt.ylabel('kor_score')

plt.show()

- 열 추가 : 데이터프레임[ '컬럼명' ] = 추가할 데이터

# sum 컬럼 추가
df['sum'] = df['kor']+df['eng']+df['math']

- 열 삭제: drop(columns = 삭제할 컬럼(들))

# no, sum 컬럼 삭제하기

df = df.drop(columns = ['no','sum'])

# df.drop(columns = ['no','sum'], inplace = True) → 이런 형태도 가능

- 컬럼명 한 번에 바꾸기: 데이터프레임.columns = 컬럼명리스트

df.columns = ['이름','국어','영어','수학']

- 특정 컬럼명 바꾸기

# 이름-->성명
df.rename(columns = {'이름':'성명'}, inplace = True)

- 마지막에 행 추가 : 데이터프레임.append(추가할 데이터) // ignore_index = True를 붙이면 인덱스 재지정

new_value = {'name':'Python','kor':80,'eng':90,'math':100}
df = df.append(new_value, ignore_index=True)

df.tail()

- 인덱스 지정하여 행 추가 (수정도 동일한 방법으로 이뤄짐)

# 인덱스 35, 34에 추가
df.loc[35] = ['aaa',70,80,90]
df.loc[34] = ['bbb',80,90,100]
df.tail()

- 행 삭제하기: 데이터프레임.drop(index = ['삭제할인덱스명']

# 34,35행 삭제
df = df.drop(index=[34,35])

# df.drop(index=[34,35],inplace=True) 동일한 결과

df.tail()


- 인덱스 이름 변경하기
(전체 인덱스)

df.index = range(100,3100,100)
df.head()

(특정 인덱스)

# 100-->'a', 200-->'b'
df = df.rename(index = {100:'a', 200:'b'}
df.head()


- 함수의 적용: 컬럼.apply(함수명) / 컬럼.apply(함수명, 매개변수명=매개변수값)

# 선택한 점수에 n점 더하기. 100점이 넘을 수 없다.
def plus_n(x,n):
    score = x+n
    if score > 100:
        score = 100
    return score

# df['eng']의 모든 점수에 n점 더하기. 100점이 넘을 수 없다.

df_copy.eng = df['eng'].apply(plus_n, n=1)
df_copy.head()

(axis=1 을 적용하면 행단위로 함수가 적용된다.(기본값: axis=0, 열단위))

# 합계 구하기
def get_sum(x):
    return x.sum()
    
# 학생 별 점수 합계
df['sum'] = df.apply(get_sum, axis = 1)

df


- 결측치 삭제하기: dropna

import pandas as pd
import numpy as np
df = pd.DataFrame([[np.nan, 2, np.nan, 0],
                   [3, 4, np.nan, 1],
                   [np.nan, np.nan, np.nan, 5],
                   [np.nan, 3, np.nan, 4]],
                  columns=list('ABCD'))
df

(결측치가 존재하는 모든 행 삭제)

df.dropna()

(결측치가 존재하는 모든 열 삭제)

df.dropna(axis=1)

- 결측치 대치하기: fillna(값)
(특정값으로 채우기)

# 0으로 채우기
df.fillna(0)

(평균값으로 채우기)

# 평균값으로 채우기(컬럼별 평균값으로 채워진다.)
df.fillna(df.mean())

(이전 값으로 채우기)

df.fillna(method='ffill')

(다음 값으로 채우기)

df.fillna(method='bfill')

(컬럼별로 대치할 값을 지정)

df.fillna({'A':0,'B':1,'C':2})

- 자료형 변환: astype('자료형')

# 실수형으로 변환
df = df.astype('float64')

# 문자열로 변환
df = df.astype('str')

# 정수형으로 변환 (문자열에서 정수로 가려면 float거쳐야 한다)
df = df.astype('float').astype('int')


- 자료형이 혼합된 컬럼을 숫자로 변경: numeric(컬럼, errors=' ignore / coerce / raise ')

# ignore:숫자료 변경할 수 없는 데이터가 있으면 작업하지 않음
pd.to_numeric(s2, errors='ignore')
# coerce:숫자로 변경할 수 없는 값이 NaN으로 설정
pd.to_numeric(s2, errors='coerce')
# raise : 숫자로 변경할 수 없는 값이 있으면 에러발생(default)
pd.to_numeric(s2, errors='raise')

# → 기본값. 에러남

- 시계열 데이터로 변경: pd.to_datetime('컬럼')

df['출생'] = pd.to_datetime(df['출생'])
# 둘 다 결과는 같다.
df['출생'] = df['출생'].astype('datetime64')


- 카테고리형 다루기: 기본 데이터타입 외 카테고리로 따로 지정해 관리. (용량 ↓, 효율)

# 평균점수 average 컬럼 추가
df['average'] = round((df['kor'] + df['eng'] + df['math'])/3,1)

# 평균점수에 따른 grade 컬럼 추가
def get_grade(x):
    if x>=90:
        return 1
    elif x>=80:
        return 2
    elif x>=70:
        return 3
    elif x>=60:
        return 4
    else:
        return 5
    
df['grade'] = df['average'].apply(get_grade)
df.head()

# 자료형 변환으로 카테고리형으로 변환
df['grade'] = df['grade'].astype('category')
df['grade'].dtypes

(카테고리 이름 바꾸기)

df['grade'].cat.categories = ['a','b','c','d']
df.head()

(누락된 카테고리 바꾸기)

df['grade'] = df['grade'].cat.set_categories(['a','b','c','d','f'])
df.grade.dtypes

- 시계열자료 다루기

# 출생 컬럼의 연도
df['출생'].dt.year

# 출생 컬럼의 달
df['출생'].dt.month

# 출생 컬럼의 일자
df['출생'].dt.day

- 날짜 계산하기

# 사망나이 컬럼 만들기
df['사망나이'] = df['사망'].dt.year - df['출생'].dt.year
df

- 요일, 월 이름 노출: strftime(' %a / %A / %w / %b / %B ')
(요약요일 / 긴 요일 / 숫자요일(0~6) / 요약 월 / 긴 월)

# 출생월 컬럼 추가하기
df['출생월'] = df['출생'].dt.strftime('%b')
df


- datetime 자료형을 인덱스로 만들어 사용

# 출생 컬럼을 인덱스로 만들기
df.index = df['출생']

# 1955년 2월 출생 데이터 추출하기
df.loc['1955-02']

- 데이터프레임 행을 기으로 연결하기: pd.concat([ '데이터프레임 리스트' ])

# 샘플 데이터
df1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])
df2 = pd.DataFrame([['c', 3], ['d', 4]], columns=['letter', 'number'])
df3 = pd.DataFrame([['e', 5, '!'], ['f', 6, '@']], columns=['letter', 'number', 'etc'])

(컬럼명 기준으로 연결하기)

# 컬럼명 기준으로 연결하기
df_rowconcat = pd.concat([df1,df2,df3])
df_rowconcat

( 컬럼명 기준 연결, 공통된 컬럼만 남기기 (inner join) )

df_rowconcat = pd.concat([df1,df2,df3],join='inner', ignore_index=True) # 마지막은 인덱스 재지정
df_rowconcat 
# inner join!

- 데이터프레임 열을 기준으로 연결하기

# 샘플 데이터
df4 = pd.DataFrame({'age':[20,21,22]},index = ['amy','james','david'])
df5 = pd.DataFrame({'phone':['010-111-1111','010-222-2222','010-333-3333']},index = ['amy','james','david']
)
df6 = pd.DataFrame({'job':['student','programmer','ceo','designer']},index = ['amy','james','david','J']
)

(인덱스 기준으로 연결하기)

df_column_concat = pd.concat([df4,df5,df6],axis=1)
df_column_concat

( 인덱스 기준 연결, 공통된 컬럼만 남기기 (inner join) )

df_column_concat = pd.concat([df4,df5,df6],axis=1,join='inner')
df_column_concat


- 공통된 열을 기준으로 연결: pd.merge(left, right, on, how='연결방법')

# name을 기준으로 연결, how = 'inner'(default)
pd.merge(df7,df8,on='name')
# how = 'outer'
pd.merge(df7,df8,on='name', how ='outer')

# outer join

(왼쪽 데이터프레임 기준으로 연결)

pd.merge(df7,df8,on='name', how ='left')

# left outer join

(오른쪽 데이터프레임 기준으로 연결)

pd.merge(df7,df8,on='name', how ='right')

# right outer join

하루 평:
모르는 것만 정리하자고 했지만, Pandas를 접하는 것은 처음이라 거의 모든 내용을 정리하게 됐다. 정리하면서의 목적은 구글링 대신 내 블로그를 찾을 수 있게 하자는 것. 익숙해질 수 있게 자주 들어와서 가볍게 보며 복습해야겠다.






이상으로 1주 3일차의 TIL포스팅을 마치겠다.