# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# %matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# ## Generate Dataset

# +
and_data = [
    {'x1': 0, 'x2': 0, 'y' : 0},
    {'x1': 1, 'x2': 0, 'y' : 0},
    {'x1': 0, 'x2': 1, 'y' : 0},
    {'x1': 1, 'x2': 1, 'y' : 1},
]

and_data = pd.DataFrame.from_dict(and_data)

plt.scatter(and_data['x1'], and_data['x2'], c=and_data['y'])

print(and_data.shape)
and_data.head()

# +
or_data = [
    {'x1': 0, 'x2': 0, 'y' : 0},
    {'x1': 1, 'x2': 0, 'y' : 1},
    {'x1': 0, 'x2': 1, 'y' : 1},
    {'x1': 1, 'x2': 1, 'y' : 1},
]

or_data = pd.DataFrame.from_dict(or_data)

plt.scatter(or_data['x1'], or_data['x2'], c=or_data['y'])

print(or_data.shape)
or_data.head()

# +
xor_data = [
    {'x1': 0, 'x2': 0, 'y' : 0},
    {'x1': 1, 'x2': 0, 'y' : 1},
    {'x1': 0, 'x2': 1, 'y' : 1},
    {'x1': 1, 'x2': 1, 'y' : 0},
]

xor_data = pd.DataFrame.from_dict(xor_data)

plt.scatter(xor_data['x1'], xor_data['x2'], c=xor_data['y'])

print(xor_data.shape)
xor_data.head()


# -

# ### Define Sigmoid

def sigmoid(n):
    return 1 / (1 + np.exp(-n))


# +
xx = np.linspace(-10, 10, num=21)
yy = sigmoid(xx)

plt.plot(xx, yy)


# -

# ### Single layer Neural Network

def gradient_descent(X, y, num_epoch=100, learning_rate=1.0):
    num_features = X.shape[1]

    w = np.random.uniform(-1.0, 1.0, size=num_features)
    b = np.random.uniform(-1.0, 1.0)

    for epoch in range(num_epoch):
        y_predict = X.dot(w) + b
        y_predict = sigmoid(y_predict)

        predict = y_predict >= 0.5
        error = (predict != y).mean()

        print("{0} error = {1:.5f}".format(epoch, error))

        if error == 0.00:
            break

        w = w - learning_rate * (y_predict - y).dot(X)
        b = b - learning_rate * (y_predict - y).mean()

    return w, b, error


# ### And Data

# +
data = and_data

X = data[["x1", "x2"]].values
y = data["y"].values

w, b, error = gradient_descent(X, y)

print("----" * 10)
print("error = {0:.5f}".format(error))

# +
xx = np.linspace(0.0, 1.0, num=11)
yy = -1.0 * (w[0] * xx + b) / w[1]

plt.scatter(data["x1"], data["x2"], c=y)
plt.plot(xx, yy)
# -

# ### Or Data

# +
data = or_data

X = data[["x1", "x2"]].values
y = data["y"].values

w, b, error = gradient_descent(X, y)

print("----" * 10)
print("error = {0:.5f}".format(error))

# +
xx = np.linspace(0.0, 1.0, num=11)
yy = -1.0 * (w[0] * xx + b) / w[1]

plt.scatter(data["x1"], data["x2"], c=y)
plt.plot(xx, yy)
# -

# ### XOR Data

# +
data = xor_data

X = data[["x1", "x2"]].values
y = data["y"].values

w, b, error = gradient_descent(X, y)

print("----" * 10)
print("error = {0:.5f}".format(error))

# +
xx = np.linspace(0.0, 1.0, num=11)
yy = -1.0 * (w[0] * xx + b) / w[1]

plt.scatter(data["x1"], data["x2"], c=y)
plt.plot(xx, yy)

# +
x1 = data["x1"].values
x2 = data["x2"].values

# np.invert(x1)
flipped_x1 = (x1 == 0).astype('int')
flipped_x2 = (x2 == 0).astype('int')

new_x1 = flipped_x1 & x2
new_x2 = x1 & flipped_x2

plt.scatter(new_x1, new_x2, c=y)

new_xor_data = pd.DataFrame({'x1': new_x1, 'x2': new_x2, 'y': y})
new_xor_data

# +
data = new_xor_data

X = data[["x1", "x2"]].values
y = data["y"].values

w, b, error = gradient_descent(X, y)

print("----" * 10)
print("error = {0:.5f}".format(error))

# +
xx = np.linspace(0.0, 1.0, num=11)
yy = -1.0 * (w[0] * xx + b) / w[1]

plt.scatter(data["x1"], data["x2"], c=y)
plt.plot(xx, yy)
# -

# ### Polynomial

# +
x1 = xor_data["x1"]
x2 = xor_data["x2"]

x3 = x1 * x1
x4 = x1 * x2
x5 = x2 * x2

polynomial_xor_data = {
    'x1': x1,
    'x2': x2,
    'x3': x3,
    'x4': x4,
    'x5': x5,
    'y': y,
}

polynomial_xor_data = pd.DataFrame(polynomial_xor_data)
polynomial_xor_data

# +
data = polynomial_xor_data

X = data[["x1", "x2", "x3", "x4", "x5"]].values
y = data["y"].values

w, b, error = gradient_descent(X, y)

print("----" * 10)
print("error = {0:.5f}".format(error))
# -

# ### Multi-layer Neural Network

# +
data = xor_data

X = data[["x1", "x2"]].values
y = data["y"].values
y = y.reshape(4, 1)

# +
num_epoch = 300
learning_rate = 1.0

w1 = np.random.uniform(low=0.0, high=1.0, size=(2, 3))
w2 = np.random.uniform(low=0.0, high=1.0, size=(3, 1))

b1 = np.random.uniform(low=0.0, high=1.0, size=(1, 3))
b2 = np.random.uniform(low=0.0, high=1.0, size=(1, 1))

for epoch in range(num_epoch):
    a1 = X.dot(w1) + b1
    z1 = sigmoid(a1)
    a2 = z1.dot(w2) + b2
    z2 = sigmoid(a2)

    y_predict = z2

    predict = y_predict >= 0.5
    error = (predict != y).mean()

    if epoch % 10 == 0:
        print("{0:3} error = {1:.5f}".format(epoch, error))

    if error == 0.00:
        break

    d2 = z2 - y
    d1 = d2.dot(w2.T) * z1 * (1 - z1)
    
    w2 = w2 - learning_rate * z1.T.dot(d2)
    w1 = w1 - learning_rate * X.T.dot(d1)

    b2 = b2 - learning_rate * d2.mean(axis=0)
    b1 = b1 - learning_rate * d1.mean(axis=0)
    
print("----" * 10)
print("{0:3} error = {1:.5f}".format(epoch, error))
# -

# ### Result

# +
a1 = X.dot(w1) + b1
z1 = sigmoid(a1)
a2 = z1.dot(w2) + b2
z2 = sigmoid(a2)

y_predict = z2

predict = y_predict >= 0.5

data["y(predict)"] = predict.astype('int')
data
# -



StarcoderdataJupyterScriptsDedupFiltered