<jupyter_start><jupyter_text>**밑바닥부터 시작하는 데이터과학**Data Science from Scratch- https://github.com/joelgrus/data-science-from-scratch/blob/master/first-edition/code-python3/simple_linear_regression.py  **필요한 함수들의 호출**작업에 필요한 함수들 호출하기<jupyter_code># with open('data.json', 'r') as f:
#     data = json.load(f)
# data['x'] = x
# with open('data.json', 'w') as f:
#     f.write(json.dumps(data))    
# stats.py
def dot(v, w):
    return sum(v_i * w_i for v_i, w_i in zip(v, w))

def standard_deviation(x):
    return math.sqrt(variance(x))

def median(v):
    n = len(v)
    sorted_v = sorted(v)
    midpoint = n // 2

    if n % 2 == 1:
        return sorted_v[midpoint]
    else:
        lo = midpoint - 1
        hi = midpoint
        return (sorted_v[lo] + sorted_v[hi]) / 2

def mean(x):
    return sum(x) / len(x)

def de_mean(x):
    x_bar = mean(x)
    return [x_i - x_bar for x_i in x]

def sum_of_squares(v):
    return dot(v, v)

def variance(x):
    n = len(x)
    deviations = de_mean(x)
    return sum_of_squares(deviations) / (n - 1)

def covariance(x, y):
    n = len(x)
    return dot(de_mean(x), de_mean(y)) / (n - 1)


def correlation(x, y):
    stdev_x = standard_deviation(x)
    stdev_y = standard_deviation(y)
    if stdev_x > 0 and stdev_y > 0:
        return covariance(x, y) / stdev_x / stdev_y
    else:
        return 0 # if no variation, correlation is zero
# linear_algebra.py
def dot(v, w):
    return sum(v_i * w_i for v_i, w_i in zip(v, w))

def vector_add(v, w):
    return [v_i + w_i for v_i, w_i in zip(v,w)]
# gradient_descent.py
def scalar_multiply(c, v):
    return [c * v_i for v_i in v]

def in_random_order(data):
    indexes = [i for i, _ in enumerate(data)]  # create a list of indexes
    random.shuffle(indexes)                    # shuffle them
    for i in indexes:                          # return the data in that order
        yield data[i]

def minimize_stochastic(target_fn, gradient_fn, x, y, theta_0, alpha_0=0.01):
    data  = list(zip(x, y))
    theta = theta_0                             # initial guess
    alpha = alpha_0                             # initial step size
    min_theta, min_value = None, float("inf")   # the minimum so far
    iterations_with_no_improvement = 0

    while iterations_with_no_improvement < 100:
        value = sum( target_fn(x_i, y_i, theta) for x_i, y_i in data )
        if value < min_value:
            min_theta, min_value = theta, value
            iterations_with_no_improvement = 0
            alpha = alpha_0
        else:
            iterations_with_no_improvement += 1
            alpha *= 0.9
        for x_i, y_i in in_random_order(data):
            gradient_i = gradient_fn(x_i, y_i, theta)
            theta = vector_subtract(theta, scalar_multiply(alpha, gradient_i))
    return min_theta
# linear_regression.py
def total_sum_of_squares(y):
    return sum(v ** 2 for v in de_mean(y))<jupyter_output><empty_output><jupyter_text>**15장 다중 회귀분석**데이터가 선형관계에 있는경우, 단순 회귀분석을 통해서 관계내용을 자세하게 살펴볼 수 있습니다  **1 모델**$ y_i $ 는 사용자 **i** 가 매일 사이트 시간이며, $x_i$ 는 사용자 **i** 의 친구수이고, $\varepsilon_i$ 는 오차를 의미합니다$$ y_i =  \beta x_i + \alpha + \varepsilon_i $$<jupyter_code># linear_algebra.py
def vector_subtract(v, w):
    return [v_i - w_i for v_i, w_i in zip(v,w)]

# /beta : 파라미터 벡터는
# /alapha : 상수항
def predict(alpha, beta, x_i):
    return beta * x_i + alpha

def predict(x_i, beta):
    return dot(x_i, beta)<jupyter_output><empty_output><jupyter_text>**2 최소자승법에 대한 몇 가지 추가 가정**최소자승법은 **단순회귀분석** 모델로 $\beta_1$ 을 **과소평가 모델로 편향** 됩니다 1. $x$ 열은 서로 일차독립을 해야 한다1. $x$ 의 모든 열은 $\varepsilon$ (오류) 와 상관이 없다1. 대신 잘못된 추정들은 $\beta$ (beta) 로 추정을 합니다  **3 모델 학습하기**오류제곱의 합을 최소로 하는 $\beta$ 를 찾기 위해 SGD (Stochastic Gradient Descent) 를 사용 합니다<jupyter_code>def error(x_i, y_i, beta):
    return y_i - predict(x_i, beta)

def squared_error(x_i, y_i, beta):
    return error(x_i, y_i, beta) ** 2

# 1번째 오류 제곱의 beta 기울기 계산
def squared_error_gradient(x_i, y_i, beta):
    return [-2 * x_ij * error(x_i, y_i, beta)
            for x_ij in x_i]

# SGD 를 활용한 최적의 Beta 계산함수
def estimate_beta(x, y):
    beta_initial = [random.random() for x_i in x[0]]
    return minimize_stochastic(squared_error,
                               squared_error_gradient,
                               x, y,
                               beta_initial,
                               0.001)
import json, random, math, re
with open('./data/data.json', 'r') as f:
    data = json.load(f)

x                  = data['x']
daily_minutes_good = data['daily_minutes_good']
random.seed(0)
beta               = estimate_beta(x, daily_minutes_good)
print("beta :{}\n체류시간(분): {:.4f} + {:.4f}, 친구수: {:.4f} 근무시간: {:.4f}".format(
    beta, beta[0], beta[1], beta[2], beta[3]))<jupyter_output>beta :[30.619881701311712, 0.9702056472470465, -1.8671913880379478, 0.9163711597955347]
체류시간(분): 30.6199 + 0.9702, 친구수: -1.8672 근무시간: 0.9164<jupyter_text>**4 모델 해석하기**1. 모든것이 동일할 때 **친구 1명이 증가** 하면 **체류시간은 0.97분 증가** 합니다1. 근무시간이 동일할 때 **근무 시간이 1시간 증가** 하면 **체류시간은 2분 감소** 합니다1. 박사 학위를 취득한 경우에는 **하루평균 1분** 더 체류 합니다  **5 적합성 (Goodness of fit)**- 오차를 측정을 위해서는 1. $\varepsilon_1$ 는 **독립**1. **평균** 은 01. **표준편차** $\sigma$ 는 **정규분포의 확률변수** 라는 가정이 필요<jupyter_code># 최적의 다중 회귀분석 : 단순회귀보다 작은 오류값을 갖는다
# 모델의 R^2 을 다시 계산하면 0.68 까지 증가함을 알 수 있습니다
def multiple_r_squared(x, y, beta):
    sum_of_squared_errors = sum(error(x_i, y_i, beta)**2
                                for x_i, y_i in zip(x, y))
    return 1.0 - sum_of_squared_errors / total_sum_of_squares(y)

print("r-squared :", multiple_r_squared(x, daily_minutes_good, beta))<jupyter_output>r-squared : 0.6800074955952597<jupyter_text>**6 Bootstrap**알 수 없는 분포에서 생성된 표본 데이터가 주어진 경우 데이터를 확대하는 방법- **중복 허용된 대추출 방식** 을 반복하여 **새로운 데이터 각 항목을 추가/ 생성** 하는 방법 입니다<jupyter_code># len(data) 개의 항목을 중복 허용한 무작위 재추출
def bootstrap_sample(data):
    return [random.choice(data) for _ in data]

# num_sample 의 bootstrap 샘플에 대해 stats_fn 을 적용
def bootstrap_statistic(data, stats_fn, num_samples):
    return [stats_fn(bootstrap_sample(data))
            for _ in range(num_samples)]

# 101 개의 데이터가 모두 100 에 인접 : 표준편차가 0에 수렴
close_to_100 = [99.5 + random.random() for _ in range(101)]

%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(bootstrap_statistic(close_to_100, median, 100))
plt.title("bootstrap_statistic(close_to_100, median, 100):")
plt.show()
# 101 개의 데이터 중, 50 개는 0 에 근접, 50 개는 200 에 근접 : 표준편차가 100에 수렵
far_from_100 = ([99.5 + random.random()] +
                [random.random() for _ in range(50)] +
                [200 + random.random() for _ in range(50)])

plt.plot(bootstrap_statistic(far_from_100, median, 100))
plt.title("bootstrap_statistic(far_from_100, median, 100)")
plt.show()<jupyter_output><empty_output><jupyter_text>**7 계수의 표준 오차**계수의 표준오차를 추정시 **bootstrap** 을 적용할 수 있습니다<jupyter_code># probability.py
def normal_cdf(x, mu=0,sigma=1):
    return (1 + math.erf((x - mu) / math.sqrt(2) / sigma)) / 2
%%time
# so that you get the same results as me
def estimate_sample_beta(sample):
    x_sample, y_sample = list(zip(*sample)) # zip 자료풀기
    return estimate_beta(x_sample, y_sample)

random.seed(0)
bootstrap_betas = bootstrap_statistic(
    list(zip(x, daily_minutes_good)), estimate_sample_beta, 100)

bootstrap_standard_errors = [
    standard_deviation([beta[i] for beta in bootstrap_betas])
    for i in range(4)]

# 상수, 친구 수, 근무시간, 박사학위여부
bootstrap_standard_errors 
def p_value(beta_hat_j, sigma_hat_j):
    if beta_hat_j > 0:
        # 만약 계수가 양수인 경우, 더 큰값이 발생할 확률에 2를 곱한다
        return 2 * (1 - normal_cdf(beta_hat_j / sigma_hat_j))
    else:
        # 아니면 더 작은값 발생할 확률에 2를 곱한다
        return 2 * normal_cdf(beta_hat_j / sigma_hat_j)

print("p-value>>>\n상수: {}\n친구의 수: {}\n근무시간: {}\n박사취득여부: {}".format(
    p_value(30.63, 1.174), p_value(0.972, 0.079),
    p_value(-1.868, 0.131), p_value(0.911, 0.990)))<jupyter_output>p-value>>>
상수: 0.0
친구의 수: 0.0
근무시간: 0.0
박사취득여부: 0.35746719881669264<jupyter_text>**8 Regularization**다양한 데이터를 취합하면 Overfitting 문제가 생길 수 있습니다.1. 때문에 적당히 **3개의 변수를 생성** 하는게 유용 합니다1. **Regularization** 은 **beta** 가 클수록 모델에 패널티를 추가해 최적의 모델을 생성합니다1. **L2** 정규화 방식인 **ridge regression** 은 **beta_i** 를 제곱한 값의 합에 비례하는 패널치를 추가 합니다<jupyter_code># alpha는 패널티의 강도를 조절하는 변수 입니다
def ridge_penalty(beta, alpha):
    return alpha * dot(beta[1:], beta[1:])

# beta 를 사용할 때 오류와 패널티의 합을 추정
def squared_error_ridge(x_i, y_i, beta, alpha):
    return error(x_i, y_i, beta) ** 2 + ridge_penalty(beta, alpha)
# 패널티의 기울기
def ridge_penalty_gradient(beta, alpha):
    return [0] + [2 * alpha * beta_j for beta_j in beta[1:]]

# i번 오류 제곱과 패널티 합의 기울기
def squared_error_ridge_gradient(x_i, y_i, beta, alpha):
    return vector_add(squared_error_gradient(x_i, y_i, beta),
                      ridge_penalty_gradient(beta, alpha))

# 패널티가 alpha 인 ridge 회귀를 경사 하강법으로 학습 합니다
from functools import partial
def estimate_beta_ridge(x, y, alpha):
    beta_initial = [random.random() for x_i in x[0]]
    return minimize_stochastic(
        partial(squared_error_ridge, alpha=alpha),
        partial(squared_error_ridge_gradient, alpha=alpha),
        x, y, beta_initial, 0.001)

def lasso_penalty(beta, alpha):
    return alpha * sum(abs(beta_i) for beta_i in beta[1:])

random.seed(0)
for alpha in [0.0, 0.01, 0.1, 1, 10]:
    beta = estimate_beta_ridge(x, daily_minutes_good, alpha=alpha)
    print("alpha: {}\nbeta: {}".format(alpha, beta))
    print("dot(beta[1:], beta[1:]): {:.5f}".format(dot(beta[1:], beta[1:])))
    print("r-squared: {:.5f}\n".format(multiple_r_squared(x, daily_minutes_good, beta)))<jupyter_output>alpha: 0.0
beta: [30.619881701311712, 0.9702056472470465, -1.8671913880379478, 0.9163711597955347]
dot(beta[1:], beta[1:]): 5.26744
r-squared: 0.68001

alpha: 0.01
beta: [30.55985204967343, 0.9730655363505671, -1.8624424625144256, 0.9317665551046306]
dot(beta[1:], beta[1:]): 5.28374
r-squared: 0.68001

alpha: 0.1
beta: [30.894860179735474, 0.9490275238632391, -1.8501720889216575, 0.5325129720515789]
dot(beta[1:], beta[1:]): 4.60736
r-squared: 0.67973

alpha: 1
beta: [30.666778908554885, 0.908635996761392, -1.6938673046100265, 0.09370161190283018]
dot(beta[1:], beta[1:]): 3.70359
r-squared: 0.67571

alpha: 10
beta: [28.372861060795607, 0.7307660860322116, -0.9212163182015426, -0.018495551723207087]
dot(beta[1:], beta[1:]): 1.38300
r-squared: 0.57521
{'fraction_non_alphanumeric': 0.13467718375693835, 'fraction_numerical': 0.07605414353880612, 'mean_word_length': 3.3333333333333335, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 34, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '650849', 'license': 'MIT', 'n_tokens_mistral': 5442, 'n_tokens_neox': 5480, 'n_words': 1084, 'path': '14.MultipleRegression.ipynb', 'repo_name': 'YongBeomKim/data-science-from-scratch', 'size': '10269'}