230307 이진 분류
pd.read_csv에서 index 지정할 때, index_col= 파라미터 주기 (idx or column name)
train = pd.read_csv(data_path + 'train.csv', index_col='id')
train = pd.read_csv(data_path + 'train.csv', index_col=0)
df.head().T를 이용하면 행 열 뒤집을 수 있음
범주형 데이터 이진분류시 작업 순서
1. 데이터 불러오기
2. 데이터 파악
.info(), .shape() 적극 이용
데이터 종류가 많을 경우 함수로 만들어서 확인하기,
3. 분포 확인 : 시각화
- 분포 확인하기 (countplot, pointplot) 활용
- 100% 비율 중 얼마나 차이 나는지 파악, 한쪽으로 쏠리면(왜도가 한쪽으로 있으면) 정규화(normalize)하기
4. 피처 엔지니어링
- 새로 파일 받아서(?, 상황에 따라) concat 후 작업
- data 양이 많으면 먼저 drop부터 시키고 작업하기 (메모리 문제)
5. 모델 성능 개선
- 피처 인코딩 (원-핫 인코딩)
tip ) patches 돌면서 각 사각형의 넓이 파악하도록 하는 함수
write_percent(ax, len(train)) <- 이런식으로 사용
-> 막대 상단에 비율을 표시할 때 이용하기
# patches를 돌면서 각 사각형의 넓이 파악 하도록 하는 함수
def write_percent(ax, total_size):
'''도형 객체를 순회하며 막대 상단에 비율 표시'''
for patch in ax.patches:
height = patch.get_height() # 도형 높이 (데이터 개수)
width = patch.get_width() # 도형 너비
left_coord = patch.get_x() # 도형 왼쪽 테두리의 X축 위치
percent = height/total_size*100 # 타깃값 비율
#(x,y) 좌표에 텍스트 입력
ax.text(
x=left_coord + width/2.0, #x축 위치
y=height + total_size*0.001, # y축 위치. 위에 살짝 틈을 주기 위해서
s=f'{percent:1.1f}%', #텍스트
ha='center', #가운데 정렬
)
격자 나눌 때 일일히 안주고 css 처럼 grid로 처리가능
import matplotlib.gridspec as gridspec #여러 그래프를 격자 배치
grid = gridspec.GridSpec(3,2) # subplot 3행 2열
data_columns = ['col1','col2',...]
for idx, data_ in enumerate(data_columns):
ax = plt.subplot(grid[idx])
sns.countplot(x=data_, data=train, hue='target', palette='pastel', ax=ax)
명목형 표준 분포에서 교차분석시 pd.crosstab 이용
pd.crosstab(train['col1'], train['target']) # 배열 비교
비율로 표시 -> 백분율
pd.crosstab(train['col1'], train['target'], normalize='index')*100
두 데이터 분포 같이 확인 할 때,
x 축 공유 y 축 공유하지 않는 새로운 축 생성시 .twinx() 이용
ax = plt.subplot(grid[idx])
ax2 = ax.twinx()
ax2 = sns.pointplot(
x=feature, y=1, data=crosstab, order=crosstab[feature].values, #순서
color = 'black', #색상
# legend=False, #범례 표시X
)
ax2.set_ylim(crosstab[1].min() - 5 , crosstab[1].max()*1.1) # ylim = y limit , 이걸 지정해야 y축 단위가 제대로 나옴
# y가 보이는 범위 최솟값 -5 ~ 최대값 * 1.1
ax2.set_ylabel('Target 1 Ration(%)')
※ 명목형 데이터의 순서를 지정하는 방법
-> data type을 object 에서 category(순서가 있는 object type)으로 바꿔버림
from pandas.api.types import CategoricalDtype
ord_1_value = ['새벽', '아침', '점심', '저녁', '밤']
ord_1_dtype = CategoricalDtype(categories=ord_1_value, ordered=True)
#데이터 타입 변경 (순서가 있는 데이터 타입)
train['ord_1'] = train['ord_1'].astype(ord_1_dtype)
작업시 체크할 사항
# 결측치가 있는지 없는지
# 모든 피쳐가 중요!!! ??(이건 잘 몰라서 뺄 수 없기 때문에!)_도메인 지식에 따라 달라짐
# 이진, 명목형(순서X), 순서형 피처 인코딩
# 각 피처별 분포와 target별 분포 설명
원-핫 인코딩 한번에
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder()
all_data_encoded = encoder.fit_transform(all_data) # 원-핫 인코딩 적용
여기서 all_data_encoded는 데이터 프레임이 아님 array에 가까운 다른 데이터
-> 데이터 변환 끝나면 습관처럼, shape, type 찍어보기
※ LogisticRegression 모델은 성능으로 뭐에 얼마나 가까운 명확하게 확인 가능
데이터가 n일 확률 -> 비스무리한 것을 다 '1'로 볼지(재현율 높게), 일정 확률 이상인 값만 '1'로 볼지(정밀도 높게) 선택 가능
logistic_model.predict_proba(X_valid) # 뭐에 더 얼마나 가까운지
logistic_model.predict(X_valid) # 뭐에 더 가까운지
roc_auc_score -> roc 수치로 바꿔줌
from sklearn.metrics import roc_auc_score #roc를 수치로 바꿔줌
#line -> 예측 어려운 것, ┌ -> 예측 좋은 것, 둥근 선 보통
roc_auc = roc_auc_score(y_valid, y_valid_preds)
print(f'검증 데이터 ROC AUC : {roc_auc:.4f}')
각각 좌측부터, roc 예측이 안 좋은 것, 우측(이런 형태로 바꿔줌)으로 갈수록 좋은 것
카테고리 적을 때는 dict과 map 이용해 인코딩
ord1dict = {'새벽':0, '아침':1, '점심':2, '저녁':3, '밤':4}
all_data['ord_1'] = all_data['ord_1'].map(ord1dict)
카테고리 양이 엄청 많을 경우
OrdinalEncoder import 해서 사용하
# 카테고리 양이 많을 경우
from sklearn.preprocessing import OrdinalEncoder
ord_tt = ['ord_2','ord_3','ord_4']
ord_encoder = OrdinalEncoder()
all_data[ord_tt] = ord_encoder.fit_transform(all_data[ord_tt])
데이터 양이 많을 때 인코딩 데이터와 스케일링 데이터 합치는 방법
scipy.sparse 라이브러리 이용, format 값만 주면됨, hstack 안에 리스트 형태로 데이터 받
# ord 인코딩 데이터와 스케일링 데이터 합치기
# 파이썬 코드로만 작업하면 memory 가 없어서 죽어버릴 수 있음
# 라이브러리 이용하기 scipy.sparse
from scipy import sparse
# 인코딩 및 스케일링 된 피처 합치기
all_data_sprs = sparse.hstack(
[sparse.csr_matrix(all_data),encoded_nom_matrix, encoded_date_matrix], # 전체 데이터에 대해서 리스트로 묶기
format = 'csr' # 'coo' or 'csr' 압축을 어떻게 할지, 메모리 사용량 줄이기
)