다중 할당(Multiple Assignment)
2개 이상의 값을 2개 이상의 변수에 동시에 할당하는 것
a,b = 1,2
print(a) # 1
print(b) # 2
좀 더 복잡한 경우를 생각해보자
class SingleLinkedList:
def __init__(self, name, val=0, next=None) -> None:
self.name = name
self.val = val
self.next = next
def __repr__(self):
return self.name
s1 = SingleLinkedList(name='s1', val=1)
s2 = SingleLinkedList(name='s2', val=2, next=s1)
s3 = SingleLinkedList(name='s3', val=3, next=s2)
a = None
a.next
→ a는 None으로 초기화가 되어 있고 당연히 a.next를 하게 되면 에러가 난다!
a = None
a, a.next = s1, s3
a = None
a, a.next, a = s1, s3, a
정답은 None
1. a가 None으로 초기화
2. 기존 s1, s3, a 값은 각각 s1, s3, None으로 초기화되어 있음
3. a = s1, a.next = s3, a=a 순서대로 실행됨
4. a에 s1의 객체가 바인딩되고 a.next에 s3의 객체가 바인딩되고, a에 None이 바인딩됨
5. 앞의 두 할당 작업이 끝나고 a에는 기존 값이던 None이 들어가게 됨
🡆 =
오른쪽 값에 기존 값을 가지고 있고, 왼쪽에 차례대로 값을 바인딩하는 것!
a = None
a, a.next, a, a.next = s1, s3, a, s2
실행하면 오류 발생
🡆 3번째 a에 None값이 들어가기 때문에 a.next는 None.next가 되어 에러
PCA 과정
(1) N차원의 데이터로부터 Covariance matrix를 생성한다.
(2) 생성된 covariance matrix에서 N개의 Eigenvector, Eigenvalue를 찾는다.
(3) 찾은 Eigenvector를 Eigenvalue가 큰 순서대로 정렬한다.
(4) 줄이기 원하는 차원 개수만큼의 Eigenvector만 남기고 나머지는 쳐낸다.
(5) 남은 Eigenvector를 축으로 하여, 데이터의 차원을 줄인다.
PC1에 직교하는 직선을 PC2로 잡기
PC1과 PC2를 축으로 하여 회전시킨 뒤 scree plot 생성
3차원 데이터가 있는데, PCA를 통해 PC1 PC2 PC3 3개의 축을 잡았고, scree plot 을 그려본 결과 PC1이 73%, PC2가 17%, PC3가 10% 를 차지한다고 해보자. 이러면 개발자에게는 차원을 줄이는 두가지 선택권이 있는 것이다.
(1) 데이터 특징의 90% 를 살리며 3차원에서 2차원으로 차원을 축소하는 선택권 (PC1, PC2 선택)
(2) 데이터 특징의 73% 를 살리며 3차원에서 1차원으로 차원을 축소하는 선택권 (PC1만 선택)
무엇을 선택할지는 현재 시스템의 리소스 상황을 고려하며 선택하면 된다.
→ 위 데이터의 variance는 (1+0+1)/3 = 2/3, 아래 데이터의 variance는 (9+0+9)/3 = 6
고차원에서의 데이터들 간의 variance를 나타내는 값
x값과 y값을 각각 x, y값의 평균의 차 곱하여 더하고(= 내적) n으로 나눠줌으로써 구할 수 있다.
※ 참고 ※
covariance를 구하기 위해 내적하는 과정은 데이터의 평균값이 0 일때만 유효하다. 2차원 데이터일 경우, 데이터의 x축 평균과 y축 평균이 모두 0이어야 하며, 0이 아닐 경우 각각 평균값을 빼주면 된다.
: x의 variance는 y의 variance보다 크므로 데이터는 가로로 길쭉한 형태가 될 것이며, x와 y의 covariance가 양수이므로 1, 3 사분면을 지나는 오른쪽 그림과 같은 형태가 된다.
: 선형변환 관점에서 바라본 covariance matrix
🡆 원점을 기준으로 골고루 퍼져있는 normal distributied 데이터에 covariance matrix를 곱해서 선형변환을 수행해주면, 아까 봤던 것처럼 covariance matrix의 특성에 맞게 데이터가 쭉 늘어나는 형태로 변하는데, 이를 "shearing"이라고 한다.
→ 단위원을 이루던 벡터는 오른쪽과 같이 1,3사분면에 걸쳐있는 넙적한 찌그러진 원이 될 것이다. 변환된 수많은 벡터들 중, 빨간색으로 표시된 벡터 2개만은 변환 전과 후의 방향이 동일한데 이 두 개의 백터가 해당 선형 시스템 방정식에 대응하는 "Eigenvector"이며, 이때 Eigenvecotr의 변환 전과 후의 길이 변화 비율을 "Eigenvalue"라고 한다.
: 선형 변환이 되기 전과 후의 방향이 같은 벡터 v가 Eigenvector이며, 변화되는 길이의 비율 λ값이 Eigenvalue이다.
factorize()
매서드df['새로운레이블인코딩컬럼명'] = pd.factorize(df['인코딩할기존컬럼명'])[0].reshape(-1,1)
사이킷런(scikitlearn)의 LabelEncoder
모듈을 이용하면, 알파벳 순서대로 알아서 라벨링함
활용 방법
# 사이킷런 패키지의 인코더 모듈 가져오기
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
# LabelEncoder는 원래 데이터프레임에 인코딩 결과를 붙여서 반환
df['새로운레이블인코딩컬럼명'] = le.fit_transform(df['인코딩할기존컬럼명'])
get_dummies()
메서드를 사용하면 빠르게 원핫 인코딩 가능dtype=int
넣기pandas.get_dummies(DataFrame \[, columns=\[변환할 컬럼명]])
→ DataFrame 에서 범주형 컬럼만 변환
OneHotEncoder
모듈을 사용
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
cols = ['age','workclass','fnlwgt','education',\
'education-num','marital-status', 'occupation',\
'relationship','race', 'gender','capital-gain',\
'capital-loss', 'hours-per-week','native-country',\
'income']
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data'
df = pd.read_csv(url, header=None, names=cols, na_values=' ?')
# df.isnull().sum()
df = df.dropna() # 결측치 제거
encoding_columns = ['workclass','education',\
'marital-status', 'occupation', 'relationship',\
'race','gender','native-country', 'income']
not_encoding_columns = ['age','fnlwgt', 'education-num',\
'capital-gain', 'capital-loss','hours-per-week']
enc_classes = {}
def encoding_label(x):
# x: 범주형 타입의 컬럼(Series)
le = LabelEncoder()
le.fit(x)
label = le.transform(x)
enc_classes[x.name] = le.classes_
# x.name: 컬럼명
return label
# 함수를 데이터셋에 적용한 결과
d1 = df[encoding_columns].apply(encoding_label)
# 연속형 변수에는 함수 적용 X
d2 = df[not_encoding_columns]
data = d1.join(d2)
merge와 join의 사용법 비교
merged_example = pd.merge(df1, df2, left_index=True,\ right_index=True) joined_example = df1.join(df2)
- merge를 사용할 때는 left_index와 right_index 파라미터를 True로 설정하여 인덱스를 기준으로 결합하도록 지정
- join은 기본적으로 인덱스를 기준으로 작동하기 때문에 별도의 지정 없이 바로 사용
🡆 join과 merge 모두 강력한 데이터프레임 결합 도구로 사용하는 상황과 요구 사항에 따라 적절한 방법을 선택해야 함!
X = data.drop(columns='income')
y = data['income']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, \
stratify=y, random_state=1)
tree = DecisionTreeClassifier(max_depth=9)
tree.fit(X_train, y_train)
pred_train = tree.predict(X_train)
pred_test = tree.predict(X_test)
acc_train = accuracy_score(y_train, pred_train)
acc_test = accuracy_score(y_test, pred_test)
print(f'학습: {acc_train}, 테스트: {acc_test}')
# 출력 결과
# 학습: 0.8621702268744376, 테스트: 0.8507017349983423
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LogisticRegression
df_cols = ['age','workclass','education', 'occupation', 'gender', \
'hours-per-week', 'income']
adult_df = df[df_cols]
# income 을 제외한 나머지 컬럼 - One-Hot Encoding
X = pd.get_dummies(adult_df[adult_df.columns[:-1]])
# income 컬럼 - Label Encoding
le = LabelEncoder()
y = le.fit_transform(adult_df['income'])
le.classes_
# 출력 결과
# array([' <=50K', ' >50K'], dtype=object)
##### 참고1 #####
ohe = OneHotEncoder()
ohe.fit(adult_df[..., np.newaxis])
ohv = ohe.transform(adult_df[..., np.newaxis])
ohv.toarray()
##### 참고2 #####
ohe = OneHotEncoder(sparse=False)
ohe.fit(adult_df[..., np.newaxis])
ohv = ohe.transform(adult_df[..., np.newaxis])
pd.DataFrame(ohv, columns=ohe.get_feature_names())
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, \
random_state=1)
lr = LogisticRegression(max_iter=1500)
lr.fit(X_train, y_train)
pred_train = lr.predict(X_train)
pred_test = lr.predict(X_test)
print(accuracy_score(y_train, pred_train))
print(accuracy_score(y_test, pred_test))
# 출력 결과
# 0.8086733566155342
# 0.8042699907174115