<jupyter_start><jupyter_text>Representing Data and Engineering FeaturesCategorical VariablesOne-Hot-Encoding (Dummy variables)<jupyter_code>pip install mglearn
import mglearn
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os
# The file has no headers naming the columns, so we pass header=None
# and provide the column names explicitly in "names"
adult_path = os.path.join(mglearn.datasets.DATA_PATH, "adult.data")
data = pd.read_csv(
    adult_path, header=None, index_col=False,
    names=['age', 'workclass', 'fnlwgt', 'education',  'education-num',
           'marital-status', 'occupation', 'relationship', 'race', 'gender',
           'capital-gain', 'capital-loss', 'hours-per-week', 'native-country',
           'income'])
# For illustration purposes, we only select some of the columns
data = data[['age', 'workclass', 'education', 'gender', 'hours-per-week',
             'occupation', 'income']]
# IPython.display allows nice output formatting within the Jupyter notebook
display(data.head())
print("Original features:\n", list(data.columns), "\n")
data_dummies = pd.get_dummies(data)
print("Features after get_dummies:\n", list(data_dummies.columns))
display(data_dummies.head())
features = data_dummies.loc[:, 'age':'occupation_ Transport-moving']
# Extract NumPy arrays
X = features.values
y = data_dummies['income_ >50K'].values
print("X.shape: {}  y.shape: {}".format(X.shape, y.shape))
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
logreg = LogisticRegression()
logreg.fit(X_train, y_train)
print("Test score: {:.2f}".format(logreg.score(X_test, y_test)))<jupyter_output>Test score: 0.81<jupyter_text>구간분할- 이 부분은 input과 output을 그리는 데이터는 동일한데 linear model을 실행시키는 데이터의 형태를 바꾸어 주어서- 선형을 사용하지만 비선형 형태의 예측값을 얻을 수도 있음을 보여주는 것입니다. 수업시간에 이야기 한 것처럼 decision tree의 경우는 원래 데이터를 나누어 가면서 학습하는 형태이기에 구간으로 나누는 방법에 크게 성능차이를 보이지 않습니다.- 비선형 관계를 가지지만 용량이 매우 크고 고차원 자료라서 linear model을 사용해야 한다면 구간 분할을 통해 모델의 성능을 높일 수 있음을 보여주는 예제입니다.<jupyter_code>from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor

X, y = mglearn.datasets.make_wave(n_samples=120)
line = np.linspace(-3, 3, 1000, endpoint=False).reshape(-1, 1)

reg = DecisionTreeRegressor(min_samples_leaf=3).fit(X, y)
plt.plot(line, reg.predict(line), label="decision tree")

reg = LinearRegression().fit(X, y)
plt.plot(line, reg.predict(line), label="linear regression")

plt.plot(X[:, 0], y, 'o', c='k')
plt.ylabel("Regression output")
plt.xlabel("Input feature")
plt.legend(loc="best")
from sklearn.preprocessing import KBinsDiscretizer
kb = KBinsDiscretizer(n_bins=10, strategy='uniform')
kb.fit(X)
print("bin edges: \n", kb.bin_edges_)<jupyter_output>bin edges: 
 [array([-2.9668673 , -2.37804841, -1.78922951, -1.20041062, -0.61159173,
       -0.02277284,  0.56604605,  1.15486494,  1.74368384,  2.33250273,
        2.92132162])]<jupyter_text>transform 을 이용해서 10개로 나누어진 구간에 각 데이터를 인코딩합니다.<jupyter_code>X_binned = kb.transform(X) 
X_binned
print(X[:10])
X_binned.toarray()[:10]<jupyter_output>[[-0.75275929]
 [ 2.70428584]
 [ 1.39196365]
 [ 0.59195091]
 [-2.06388816]
 [-2.06403288]
 [-2.65149833]
 [ 2.19705687]
 [ 0.60669007]
 [ 1.24843547]]<jupyter_text>- decision tree 와 regression model의 결과가 같게 나옵니다. - 위의 그림과 비교했을 때 decision tree는 오히려 더 움직임이 경직되고 regression model은 더 유연해진 것을 볼 수 있습니다. 구간을 나누는 것이  linear model에는 긍정적인 영향을 주지만 모든 모델에 영향을 주는 것은 아님을 알려줍니다.<jupyter_code>kb = KBinsDiscretizer(n_bins=10, strategy='uniform', encode='onehot-dense')
kb.fit(X)
X_binned = kb.transform(X)
line_binned = kb.transform(line)

reg = LinearRegression().fit(X_binned, y)
plt.plot(line, reg.predict(line_binned), label='linear regression binned')

reg = DecisionTreeRegressor(min_samples_split=3).fit(X_binned, y)
plt.plot(line, reg.predict(line_binned), label='decision tree binned')
plt.plot(X[:, 0], y, 'o', c='k')
plt.vlines(kb.bin_edges_[0], -3, 3, linewidth=1, alpha=.2)
plt.legend(loc="best")
plt.ylabel("Regression output")
plt.xlabel("Input feature")<jupyter_output><empty_output><jupyter_text>Interactions and Polynomials- 위의 그림은 각 구간별로 절편을 학습해주는 형태이기에 기울기가 나타나지 않습니다. - 각 구간별로 기울기가 나타나도록 학습해주는 것인데 구체적인 의미를 알려면 회귀 모형에 대한 설명이 필요하니 머신러닝에서 각 구간별로 구간 회귀를 만들어서 복잡한 모형에 의해 구현되는 것과 같은 효과를 얻어낼 수도 있다는 사실을 알고 필요할 때 적용해보시면 되겠습니다.<jupyter_code>X_combined = np.hstack([X, X_binned]) # add original input X
print(X_combined.shape)
reg = LinearRegression().fit(X_combined, y)

line_combined = np.hstack([line, line_binned])
plt.plot(line, reg.predict(line_combined), label='linear regression combined')

plt.vlines(kb.bin_edges_[0], -3, 3, linewidth=1, alpha=.2)
plt.legend(loc="best")
plt.ylabel("Regression output")
plt.xlabel("Input feature")
plt.plot(X[:, 0], y, 'o', c='k')<jupyter_output><empty_output><jupyter_text>기울기를 다르게 학습하도록 입력 변수 추가<jupyter_code>X_product = np.hstack([X_binned, X * X_binned]) # add interaction term
print(X_product.shape)<jupyter_output>(120, 20)<jupyter_text>- 각 구간에서의 절편과 기울기가 다르게 학습이 되었음을 알 수 있다.<jupyter_code>reg = LinearRegression().fit(X_product, y)

line_product = np.hstack([line_binned, line * line_binned])
plt.plot(line, reg.predict(line_product), label='linear regression product')

plt.vlines(kb.bin_edges_[0], -3, 3, linewidth=1, alpha=.2)

plt.plot(X[:, 0], y, 'o', c='k')
plt.ylabel("Regression output")
plt.xlabel("Input feature")
plt.legend(loc="best")<jupyter_output><empty_output><jupyter_text>다항식 항을 추가하여 다항 회귀 모델로 비선형 회귀 모델을 가능하게 함<jupyter_code>from sklearn.preprocessing import PolynomialFeatures

# include polynomials up to x ** 10:
# the default "include_bias=True" adds a feature that's constantly 1
poly = PolynomialFeatures(degree=10, include_bias=False)
poly.fit(X)
X_poly = poly.transform(X)
print("X_poly.shape: {}".format(X_poly.shape))
print("Entries of X:\n{}".format(X[:5]))
print("Entries of X_poly:\n{}".format(X_poly[:5]))
print("Polynomial feature names:\n{}".format(poly.get_feature_names()))
reg = LinearRegression().fit(X_poly, y)

line_poly = poly.transform(line)
plt.plot(line, reg.predict(line_poly), label='polynomial linear regression')
plt.plot(X[:, 0], y, 'o', c='k')
plt.ylabel("Regression output")
plt.xlabel("Input feature")
plt.legend(loc="best")<jupyter_output><empty_output><jupyter_text>원본 데이터에 복잡한 모형인 SVM을 학습하여 위의 회귀모형 결과와 비교- 다항회귀와 비슷한 복잡도를 가진 예측이 생성됨을 확인<jupyter_code>from sklearn.svm import SVR

for gamma in [1, 10]:
    svr = SVR(gamma=gamma).fit(X, y)
    plt.plot(line, svr.predict(line), label='SVR gamma={}'.format(gamma))

plt.plot(X[:, 0], y, 'o', c='k')
plt.ylabel("Regression output")
plt.xlabel("Input feature")
plt.legend(loc="best")<jupyter_output><empty_output><jupyter_text>보스톤 주택 가격 자료로 상호작용과 다항식 특성을 추가했을 때의 성능 향상을 보고자 함.<jupyter_code>from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

boston = load_boston()
X_train, X_test, y_train, y_test = train_test_split(
    boston.data, boston.target, random_state=0)

# rescale data
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
poly = PolynomialFeatures(degree=2).fit(X_train_scaled)
X_train_poly = poly.transform(X_train_scaled)
X_test_poly = poly.transform(X_test_scaled)
print("X_train.shape: {}".format(X_train.shape))
print("X_train_poly.shape: {}".format(X_train_poly.shape))
print("Polynomial feature names:\n{}".format(poly.get_feature_names()))<jupyter_output>Polynomial feature names:
['1', 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x0^2', 'x0 x1', 'x0 x2', 'x0 x3', 'x0 x4', 'x0 x5', 'x0 x6', 'x0 x7', 'x0 x8', 'x0 x9', 'x0 x10', 'x0 x11', 'x0 x12', 'x1^2', 'x1 x2', 'x1 x3', 'x1 x4', 'x1 x5', 'x1 x6', 'x1 x7', 'x1 x8', 'x1 x9', 'x1 x10', 'x1 x11', 'x1 x12', 'x2^2', 'x2 x3', 'x2 x4', 'x2 x5', 'x2 x6', 'x2 x7', 'x2 x8', 'x2 x9', 'x2 x10', 'x2 x11', 'x2 x12', 'x3^2', 'x3 x4', 'x3 x5', 'x3 x6', 'x3 x7', 'x3 x8', 'x3 x9', 'x3 x10', 'x3 x11', 'x3 x12', 'x4^2', 'x4 x5', 'x4 x6', 'x4 x7', 'x4 x8', 'x4 x9', 'x4 x10', 'x4 x11', 'x4 x12', 'x5^2', 'x5 x6', 'x5 x7', 'x5 x8', 'x5 x9', 'x5 x10', 'x5 x11', 'x5 x12', 'x6^2', 'x6 x7', 'x6 x8', 'x6 x9', 'x6 x10', 'x6 x11', 'x6 x12', 'x7^2', 'x7 x8', 'x7 x9', 'x7 x10', 'x7 x11', 'x7 x12', 'x8^2', 'x8 x9', 'x8 x10', 'x8 x11', 'x8 x12', 'x9^2', 'x9 x10', 'x9 x11', 'x9 x12', 'x10^2', 'x10 x11', 'x10 x12', 'x11^2', 'x11 x12', 'x12^2']<jupyter_text>- Ridge 는 성능이 향상되었으나 RandomForest는 성능이 오히려 조금 줄어들었음을 알 수 있다.- RandomForest는 여러 머신러닝을 연결한 모형인 앙상블에 해당하기에 성능이 대부분 아주 좋게 나온다.- 원본의 RandomForest와 상호작용과 다항식을 추가한 Ridge가 비슷한 성능을 보인다. 이는 단순한 모형에 상호작용과 다항식이 더해져서 복잡한 모형과 유사한 성능을 나타냄을 보이고자 하는 예제이다.<jupyter_code>from sklearn.linear_model import Ridge
ridge = Ridge().fit(X_train_scaled, y_train)
print("Score without interactions: {:.3f}".format(
    ridge.score(X_test_scaled, y_test)))
ridge = Ridge().fit(X_train_poly, y_train)
print("Score with interactions: {:.3f}".format(
    ridge.score(X_test_poly, y_test)))
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor(n_estimators=100).fit(X_train_scaled, y_train)
print("Score without interactions: {:.3f}".format(
    rf.score(X_test_scaled, y_test)))
rf = RandomForestRegressor(n_estimators=100).fit(X_train_poly, y_train)
print("Score with interactions: {:.3f}".format(rf.score(X_test_poly, y_test)))<jupyter_output>Score without interactions: 0.809
Score with interactions: 0.766<jupyter_text>Univariate Nonlinear Transformations- 대부분이 모형은 특성이 정규분포와 비슷할 때 최고의 성능을 낸다. - 정규분포가 아닌 경우 변환을 통해 치우침이 덜한 형태로 조정한 후 머신러닝을 적용한다.<jupyter_code>rnd = np.random.RandomState(0)
X_org = rnd.normal(size=(1000, 3))
w = rnd.normal(size=3)

X = rnd.poisson(10 * np.exp(X_org))
y = np.dot(X_org, w)
print("Number of feature appearances:\n{}".format(np.bincount(X[:, 0])))
bins = np.bincount(X[:, 0])
plt.bar(range(len(bins)), bins, color='grey')
plt.ylabel("Number of appearances")
plt.xlabel("Value")<jupyter_output><empty_output><jupyter_text>- 위와 같이 한쪽으로 치우친 특성으로 ridge를 실행하였을 때의 성능<jupyter_code>from sklearn.linear_model import Ridge
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
score = Ridge().fit(X_train, y_train).score(X_test, y_test)
print("Test score: {:.3f}".format(score))
X_train_log = np.log(X_train + 1)
X_test_log = np.log(X_test + 1)
plt.hist(X_train_log[:, 0], bins=25, color='gray')
plt.ylabel("Number of appearances")
plt.xlabel("Value")<jupyter_output><empty_output><jupyter_text>- 로그 변환으로 치우침을 제거한 후 ridge를 실행하였더니 성능이 매우 향상되었음을 확인<jupyter_code>score = Ridge().fit(X_train_log, y_train).score(X_test_log, y_test)
print("Test score: {:.3f}".format(score))<jupyter_output>Test score: 0.875<jupyter_text>Automatic Feature Selection Univariate statistics<jupyter_code>from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import SelectPercentile
from sklearn.model_selection import train_test_split

cancer = load_breast_cancer()

# get deterministic random numbers
rng = np.random.RandomState(42)
noise = rng.normal(size=(len(cancer.data), 50))
# add noise features to the data
# the first 30 features are from the dataset, the next 50 are noise
X_w_noise = np.hstack([cancer.data, noise])

X_train, X_test, y_train, y_test = train_test_split(
    X_w_noise, cancer.target, random_state=0, test_size=.5)
# use f_classif (the default) and SelectPercentile to select 50% of features
select = SelectPercentile(percentile=50)
select.fit(X_train, y_train)
# transform training set
X_train_selected = select.transform(X_train)

print("X_train.shape: {}".format(X_train.shape))
print("X_train_selected.shape: {}".format(X_train_selected.shape))<jupyter_output>X_train.shape: (284, 80)
X_train_selected.shape: (284, 40)<jupyter_text>- 80개의 특성 중 40개를 선택한 후 logistic을 실행하여 비교한 결과 변수 선택 후 성능이 향상 됨.- 항상 성능이 향상되지는 않고 성능이 좋아지지 않는 경우도 있음.<jupyter_code>from sklearn.linear_model import LogisticRegression

# transform test data
X_test_selected = select.transform(X_test)

lr = LogisticRegression(max_iter=1000)
lr.fit(X_train, y_train)
print("Score with all features: {:.3f}".format(lr.score(X_test, y_test)))
lr.fit(X_train_selected, y_train)
print("Score with only selected features: {:.3f}".format(
    lr.score(X_test_selected, y_test)))<jupyter_output>C:\Users\math\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py:762: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.

Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
  n_iter_i = _check_optimize_result(<jupyter_text>Model-based Feature Selection- 위의 일변량 분석보다 훨씬 강력한 방법이고 매우 복잡한 모델- 특성에 대한 중요도가 포함되는 지도학습 머신 러닝 모델을 이용해서 중요한 특성을 한번에 선택하게 함.- 위의 일변량 특성 선택보다 RandomForest를 사용하였을 때 향상된 성능을 보임<jupyter_code>from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier
select = SelectFromModel(
    RandomForestClassifier(n_estimators=100, random_state=42),
    threshold="median")
select.fit(X_train, y_train)
X_train_l1 = select.transform(X_train)
print("X_train.shape: {}".format(X_train.shape))
print("X_train_l1.shape: {}".format(X_train_l1.shape))
X_test_l1 = select.transform(X_test)
score = LogisticRegression(max_iter=1000).fit(X_train_l1, y_train).score(X_test_l1, y_test)
print("Test score: {:.3f}".format(score))<jupyter_output>Test score: 0.951<jupyter_text>Iterative feature selection- 반복해서 학습하여 특성을 선택하므로 모델기반보다 오래 걸림- Logistic regression 의 성능이 역시 변수 선택에 의해 향상된 결과를 보임- RandomForest 의 성능도 역시 0.951로 선택된 특성으로 logistic regression의 성능과 같다. 즉 특성 선택이 제대로 될 경우 선형모델의 성능은 RandomForest의 성능에 버금가도록 만들 수 있음을 보여줌.<jupyter_code>from sklearn.feature_selection import RFE
select = RFE(RandomForestClassifier(n_estimators=100, random_state=42),
             n_features_to_select=40)

select.fit(X_train, y_train)
X_train_rfe = select.transform(X_train)
X_test_rfe = select.transform(X_test)

score = LogisticRegression(max_iter=1000).fit(X_train_rfe, y_train).score(X_test_rfe, y_test)
print("Test score: {:.3f}".format(score))
print("Test score: {:.3f}".format(select.score(X_test, y_test))) ## Result of RandomForest<jupyter_output>Test score: 0.951
{'fraction_non_alphanumeric': 0.14442286348501665, 'fraction_numerical': 0.04266093229744728, 'mean_word_length': 6.060235063663075, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 63, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '18', 'dir': 'jupyter-structured-clean-dedup', 'id': '145579', 'license': 'MIT', 'n_tokens_mistral': 6999, 'n_tokens_neox': 7321, 'n_words': 1380, 'path': 'Assignment_09_EM/Reference/Engineering features.ipynb', 'repo_name': 'luwis93choi/ML2020_Class', 'size': '14416'}