Ch 01. Pandas
출처 입력
* 엑셀로 할 수 있는 모든 것을 할 수 있음
import pandas as pd
* Series : 1차원 데이터 배열
mylist = [1,2,3,4] pd.Series(mylist)
* DataFrame : 2차원 데이터 배열
- list로 만들기
company1 = [['삼성', 2000, '스마트폰'], ['현대', 1000, '자동차'], ['네이버', 500, '포털']] pd.DataFrame(company1) df1 = pd.DataFrame(company1) df1.columns = ['기업명', '매출액', '업종']
- dict로 만들기
company2 = {'기업명': ['삼성', '현대', '네이버'], '매출액': [2000, 1000, 500], '업종': ['스마트폰', '자동차', '포털']} df2 = pd.DataFrame(company2)
- index를 특정 column으로 지정하기
df1.index = df1['기업명']
* CSV 파일 읽어오기
- CSV : Comma Seperated Value
- 엑셀을 로딩할 수 있지만 쉼표로 구분된 csv가 속도면에서 우월함
1) 로컬에서 파일 읽어오기
from google.colab import files import io myfile = files.upload() pd.read_csv(io.BytesIO(myfile['korean-idol.csv']))
2) Google Drive에서 파일 읽어오기
- drive.mount('/content/drive')실행하고 링크 클릭 후 코드 입력
from google.colab import drive drive.mount('/content/drive') filename = '경로'
* Pandas 기본
- df.columns
- df.index
- df.info()
- df.describe() : 통계 정보(숫자형만 해당됨)
- df.shape : tuple형태로 반환
- df.head()
- df.tail()
- df.sort_index() : 인덱스를 기준으로 오름차순 정렬
- df.sort_index(ascending=False) : 내림차순으로 정렬
- df.sort_values(by='키') : 키 컬럼을 기준으로 오름차순 정렬
- df.sort_values(by='키', ascending=False)
- df.sort_values(by=['키', '브랜드평판지수']) : 1)키, 2)브랜드평판지수 컬럼 기준으로 정렬 (순서 중요)
* Column 선택
1) df['이름']
2) df["이름"]
3) df.이름
* 범위 선택
1) 단순 index에 대한 범위 선택
- df[:3] : 행 기준 0~2행 가져옴
- df.head()
2) loc
- loc[행, 열]
- df.loc[:, '이름'] : 전체 행, 이름 컬럼 가져옴
- df.loc[:, ['이름', '생년월일']] : 전체 행, 이름과 생년월일 컬럼 가져옴
- df.loc[3:8, ['이름', '생년월일']] : 3~8행, 이름과 생년월일 컬럼 가져옴
- df.loc[2:5, ['이름':'생년월일']] : 2~5행, 이름부터 생년월일 컬럼까지 가져옴
3) iloc
- iloc[행, 열] : position을 넣어야
- df.iloc[:, [0,2]] : 전체 행, 0과 2번째 컬럼 가져옴
- df.iloc[1:5, [0, 2]] : 1~4까지 행, 0과 2번째 컬럼 가져옴
- df.iloc[1:5, 1:4] : 1~4까지 행, 1~3까지 컬럼 가져옴
- loc는 인덱싱 기준이 다름을 주의
4) boolean
- numpy와 같은 원리
- df[ df['키'] > 180]
- 특정한 컬럼을 뽑고 싶을 땐?
1) 뒤에 컬럼 이름 붙이기 : df[ df['키'] > 180]['이름', '성별']
2) loc 이용하기
df.loc[df[ df['키'] > 180, '이름' : '성별'] df.loc[df[ df['키'] > 180, ['이름', '성별']]
5) isin (boolean)
- list를 정의하고 그 리스트에 있는 조건에 부합하는 데이터만 추출
my_condition = ['플레디스', 'SM'] df['소속사'].isin(my_condition) # boolean 형태로 나옴 -> False False ... df.loc[ df['소속사'].isin(my_condition) ] df.loc[ df['소속사'].isin(my_condition), '소속사' ]
* Null (결측값)
- 판다스에서는 NaN으로 표기됨
- df.info()로 데이터 개수 확인하여 결측값 확인
- df.isna()로 boolean인덱싱하여 결측값 확인
- df['그룹'].isnull() 혹은 .isnan()으로 컬럼별로 결측값 확인
- NaN이 아닌 값만 색출해내기
df['그룹'][df['그룹'].notnull()] df.loc[ df['그룹'].notnull(), ['키', '혈액형'] ]
* Copy
- 데이터프레임을 복사할 때 사용
- 원본 데이터를 유지시키고, 새로운 변수에 복사할 때는 copy()를 사용해야 함
- 그저 새로운 변수에 할당하면, 같은 메모리 주소를 참조하기때문에 원테이블의 데이터도 바뀜
- copy_df = df.copy()
* Row 추가 및 삭제
- 딕셔너리 형태의 데이터를 만들어 .append() 함수를 사용하여 추가
- 반드시 ignore_index=True 옵션을 추가해야 함
- df = df.append(~~) 로 다시 데이터프레임에 할당해 줘야 함
df = df.append({'이름': '테디', '그룹': '테디그룹', '소속사': '끝내주는소속사', '성별': '남자', '생년월일': '1970-01-01', '키': 195.0, '혈액형': 'O', '브랜드평판지수': 12345678}, ignore_index=True)
* Column 추가 및 삭제
- 단순히 새로운 컬럼을 만들고 값을 대입해주면 자동으로 생성됨
df['국적'] = '대한민국' # 데이터를 바꿀땐? df.loc[df['이름'] == '지드래곤', '국적'] = 'Korea'
* 통계값 다루기
- 데이터타입이 float, int형인 컬럼을 다룸
- df.describe()로 기본 통계값을 확인 가능
- df['키'].min()
- df['키'].max()
- df['키'].sum()
- df['키'].mean()
- 분산과 표준편차
- 분산 : ∑(데이터 - 평균)2
- 표준편차 : √(분산)
- 주로 표준편차를 많이 사용하며, 데이터가 평균으로부터 얼마나 퍼져있는지 정도를 나타내는 지표로 활용
- df['키'].var()
- df['키'].std()
- df['키'].count()
- df['키'].median()
* 피벗테이블
- 엑셀의 피벗테이블과 동일
- 데이터 열 중에서 두 개의 열을 각각 행 인덱스, 열 인덱스로 사용하여 데이터를 커스터마이즈하여 보려는 목적
- index : 행 인덱스
- columns : 열 인덱스
- values : 조회하고 싶은 값
- aggfunc : 추가 계산 옵션 (기본 : 평균)
pd.pivot_table(df, index='소속사', columns='혈액형', values='키', aggfunc=np.sum)
* Groupby (그룹별 통계)
- 데이터를 그룹으로 묶어 분석할 때 활용
- 소속사별 키의 평균, 성별 키의 평균 등 특정 그룹별 통계 및 데이터의 성질을 확인하고자 할 때
- groupby와 함께 사용하는 함수
- count(), sum(), mean(), var(), std(), min(), max()
df.groupby('소속사').mean() ### 특정 열만 출력하고 싶다면? df.groupby('혈액형')['키'].mean()
* Multi-index (복합 인덱스)
- 멀티인덱스 적용
- 행 인덱스를 복합적으로 구성하고 싶은 경우 : 인덱스를 리스트로 만들어 주자
df.groupby(['혈액형', '성별']).mean()
- 멀티인덱스된 데이터프레임을 피벗테이블로 변환
df.unstack('혈액형') # 멀티인덱스였던 혈액형, 성별 중 혈액형이 컬럼으로 가며 펴지는 기능을 함 (인덱스는 이제 성별만)
- 인덱스 초기화
- reset_index()
- 멀티인덱스로 구성된 데이터프레임의 인덱스를 초기화함
Ch 02. Pandas - 전처리
출처 입력
* fillna (결측값 채우기)
- df.info()로 누락된 값들의 갯수를 확인 가능
- 누락된 값을 특정 수로 채우려면 ?
df2 = df.copy() height = df2['키'].mean() df2['키'] = df['키'].fillna(height)
* dropna (결측값 있는 행을 제거)
df.dropna() ### 열을 없애고 싶으면? df.dropna(axis=1)
- how 옵션
- how = 'any' : 한개라도 NaN이 있는 경우 드랍
- how = 'all' : 모두 NaN인 경우 드랍
df.dropna(axis=0, how='all')
* drop_duplicates (중복값 제거)
keep 옵션으로 유지하고 싶은 데이터를 선택할 수 있음
- first : 기본값, 해당 값이 처음 나온 데이터는 유지
- last : 해당 값이 마지막으로 나온 데이터를 유지
- series 기준으로 제거
df['키'] = df['키'].drop_duplicates(keep='last')
- 행 전체를 제거
df.drop_duplicates('그룹', kee='last') # 중복된 그룹이 나오면 마지막 행을 제외한 다른 행 전체를 제거
* drop()
- 컬럼을 제거
- 제거하고자하는 컬럼명을 활용
- axis = 1
df = df.drop(['그룹', '소속사'], axis=1)
- row를 제거
- 제거하고자 하는 index를 활용
- axis = 0
df = df.drop([3,5], axis=0)
* 데이터프레임 합치기 : concat
- row 나 col 기준으로 단순하게 이어 붙이기
- 상하로 붙이기 (row 기준)
- 리스트로 합쳐주기
- sort = False 옵션을 주어 순서가 유지되도록 하기
- index가 꼬이게 되므로, reset_index() 로 인덱스를 초기화 해줘야 함
pd.concat([df, df_copy], sort=False)
- 좌우로 붙이기 (col 기준)
- axis = 1 옵션을 주기
- 만약 행의 갯수가 맞지 않는다면 NaN으로 채워짐
pd.concat([df, df2], axis=1)
* 데이터프레임 합치기2 : merge
- 특정 고유한 키(unique id)를 기준으로 병합하기
- on : 기준이 되는 column
- how : 'left', 'right', 'inner', 'outer' 총 4가지의 병합 방식
- left : 왼쪽의 데이터프레임에 키 값이 존재하면 해당 데이터를 유지, 병합한 오른쪽 데이터프레임의 값은 NaN
- inner : 두 데이터프레임에 모두 키 값이 존재하는 경우만 병함
- outer : 하나의 데이터프레임에 키 값이 존재하는 경우 모두 병합 (데이터가 없는 경우 NaN으로 대입됨)
pd.merge(df1, df2, on='이름', how='left') ## 만약 두 DataFrame에서 컬럼명이 다르다면? (Eg. 이름, 성함) pd.merge(df1, df2, left_on='이름', right_on='성함', how='outer')
* Series의 타입 변환하기
- df.info() 로 데이터타입 확인
- object : 일반 문자열
- float
- int
- category : 카테고리
- datetime : 시간
- 타입 변환
1) astype 메소드 사용
- NaN이 있는 경우 변경이 안되므로 결측치 처리를 하고 변환해야 함
df['키'].dtypes df['키'] = df['키'].fillna(180) df['키'].astype(int)
2) datetime 으로 날짜 변환하기
- 판다스 메소드인 to_datetime 사용
- 월, 일, 요일 등 날짜 정보를 세부적으로 추출하기 편리
- 약어 : dt
- 현재 날짜 col은 dtype이 object로 되어있다고 가정 -> datetime으로 변환
df['생년월일'] = pd.to_datetime(df['생년월일'])
- 월요일 : 0, 화요일 : 1, ... , 일요일 : 6
df['생년월일'].dt.year df['생년월일'].dt.month df['생년월일'].dt.day df['생년월일'].dt.hour df['생년월일'].dt.minute df['생년월일'].dt.second df['생년월일'].dt.dayofweek df['생년월일'].dt.weekofyear df['생일_년'] = df['생년월일'].dt.year df['생일_월'] = df['생년월일'].dt.month df['생일_일'] = df['생년월일'].dt.day
* Apply 함수
- series나 DataFrame에 좀 더 구체적인 로직을 적용하고 싶은 경우 활용
1) 함수를 먼저 정의해야 함
2) 정의한 함수를 인자로 넘겨줘야 함
- 반드시 return 값이 존재해야 함
- (Eg) 남자를 1, 여자를 0으로 변환하고 싶음
### 1) apply에 활용할 함수를 정의하기 def male_or_female(x): if x == '남자': return 1 elif x == '여자': return 0
### 2) 정의한 함수를 인자로 넘겨주기 df['성별_NEW'] = df['성별'].apply(male_or_female)
- (Eg) cm당 브랜드 평판지수를 구해보자 (브랜드평판지수/키)
### 1) 먼저 apply에 활용할 함수를 정의하기 def cm_to_brand(df): value = df['브랜드평판지수'] / df['키'] return value
### 2) 정의한 함수를 인자로 넘겨주기 ### 연산하는 방식을 열로 하겠다 => 한 행씩 넘겨줘 => axis=1 지정을 해야 함 df.apply(cm_to_brand, axis=1)
* Lambda
- 람다는 1줄로 작성하는 간단한 함수식으로 리턴을 명시하지 않음
f = lambda x: 1 if x == '남자' else 0 df['성별'].apply(f)
df['키/2'] = df['키'].apply(lambda x: x/2)
* Map
- 값을 매핑
- 딕셔너리 타입으로 정의해줘야 함
my_map = {'남자': 1, '여자': 0} df['성별'].map(my_map)
* 데이터프레임의 산술연산
df = pd.DataFrame({'통계': [60, 70, 80, 85, 75], '미술': [50, 55, 80, 100, 95], '체육': [70, 65, 50, 95, 100] })
통계 미술 체육 0 60 50 70 1 70 55 65 2 80 80 50 3 85 100 95 4 75 95 10
1) 컬럼과 컬럼의 연산 (+, -, *, /, %)
df['통계'] + df['미술'] + df['체육']
2) 컬럼과 숫자의 연산 (+, -, *, /, %)
df['통계'] + 10
3) 복합연산
df['통계미술합계'] = df['통계'] + df['미술'] + 10
4) axis기준 mean(), sum() 연산
df.sum(axis=0) df.mean(axis=1)
5) NaN이 있을 경우 연산
통계 미술 체육 0 60.0 50.0 70.0 1 70.0 NaN 65.0 2 NaN 80.0 50.0 3 85.0 100.0 NaN 4 75.0 95.0 100.0
df['통계'] / 2 1000 / df['통계'] df['통계'] / np.nan # NaN있으면 NaN으로 나옴
6) 데이터프레임과 데이터프레임의 연산
6-1) 문자열이 포함된 경우 : 에러 -> 제거하고 연산
6-2) 컬럼의 순서가 바뀌어있는 경우 : OK <- 컬럼명 기준으로 연산되기 때문
6-3) 행의 갯수가 다른 경우 : OK <- 빈 곳을 NaN으로 할당
* 원핫인코딩 (One-hot-encoding)
- 한개의 요소를 true, 나머지를 false로 만드는 기법
- (Eg) object데이터타입인 혈액형 col을 numerical하게 바꾸기
blood_map = { 'A': 0, 'B': 1, 'AB': 2, 'O': 3, } df['혈액형_code'] = df['혈액형'].map(blood_map)
- 머신러닝 시 문제점 발생
- '혈액형_code'값들간의 관계를 스스로 형성하게 됨
- 예를 들어, B형과 AB형을 더한게 O형이라는 없는 관계를 있는 관계로 해석함
-> 따라서, 0부터 3까지가 아닌 4개의 독립적인 column을 생성하여 요소간의 독립성을 부여해야
- get_dummies 활용
- prefix 옵션을 통해 컬럼명을 설정할 수 있음
pd.get_dummies(df['혈액형_code']) pd.get_dummies(df['혈액형_code'], prefix='혈액형') # 컬럼명이 '혈액형_0', '혈액형_1', ... 같은 형식으로 생성됨
* (예제) 부동산 데이터
- Questions:
- object: NaN이랑 ''이랑 다름? 매번 따로 처리해야 하나? 귀찮^^;; -> 광광이
- replace vs str.replace
- replace는 한 개씩밖에 못하나?
- 조건에 맞는 행 삭제
1) 조건에 맞는 데이터의 인덱스 리스트로 저장
2) drop()으로 인덱스에 맞는 행(axis=0) 삭제
idx = df.loc[df['규모구분'] < 100] df = df.drop(idx, axis=0)
Ch 03. Pandas - 시각화
출처 입력
* 시각화
- Exploratory Data Analysis (EDA) :
- 수집한 데이터가 들어왔을 떄, 이를 다양한 각도에서 관찰하고 이해하는 과정
- 통계값 등 기본적인 데이터의 특징을 파악하는 과정
- 시각화 (Visualization) : 직관적으로, 한 눈에 파악하기 쉽게 데이터 뿌려놓는 것
- df.plot()
- colab에서는 한글 깨짐
- 깨지는 현상 해결 코드 있음 -> 외울 필요는 X
* Plot 그래프
- plot은 선그래프가 기본 설정
- kind를 통해 그래프 종류 설정 가능
- line : 선 그래프 (주가 평균 데이터)
- bar : 바 그래프 (그룹별로 비교할 때)
- bath : 수평 바
- hist : 히스토그램
- kde : 커널 밀도 그래프 (hist와 비슷, 밀도를 보여줌, 부드러운 라인)
- hexbin : 고밀도 산점도 그래프 (numerical x와 y의 키 값을 넣어줘야 함, 데이터의 밀도를 추정)
- df.plot(kind = 'hexbin', x='분양가', y='연도', gridsize=20)
- box : 박스 플롯
- area : 면적 그래프 (line그래프에서 아래 면적을 다 색칠한 그래프)
- pie : 파이 그래프 (점유율)
- scatter : 산점도 그래프 (numerical x, y값을 넣어줘야, 축 지정 가능)
df['분양가'].plot(kind = 그래프종류)
- 조건을 넣어서 그래프 그리기
df_seoul_year = df_seoul.groupby('연도')['분양가'].mean().plot(kind = 'line')