Lab

14.6.2. Lab#

  • Use this assignment to practice the chapter’s concepts and coding skills in runnable Python code.

  • Sign in from the account menu before you start working on the assignment.

  • Write and run your code directly in the coding cells.

  • Multiple submissions are allowed. The highest score is kept.

### Question 1: The Nearest Neighbor
# A bank wants to predict whether a new applicant will repay a loan.
#   1. Compute the distance from applicant to each past loan, using
#      income_su and debt_su.
#   2. Print the distance to the nearest loan (rounded to 3 decimals) and
#      the 1-nearest-neighbor prediction (that loan's outcome).
# Print exactly:
# Nearest distance: 0.141
# 1-NN prediction: repaid
import numpy as np
import pandas as pd

# Past loans; both attributes are already in standard units.
loans = pd.DataFrame({
    "income_su": [1.2, 0.8, -0.3, -1.1, 0.4, -0.9, 1.5, -0.2, 0.1, -1.4],
    "debt_su": [-0.9, -0.4, 0.6, 1.3, -0.1, 0.9, -1.2, 1.0, 0.3, 0.2],
    "outcome": ["repaid", "repaid", "default", "default", "repaid",
                "default", "repaid", "default", "repaid", "default"],
})
applicant = np.array([0.0, 0.4])
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

# Past loans; both attributes are already in standard units.
loans = pd.DataFrame({
    "income_su": [1.2, 0.8, -0.3, -1.1, 0.4, -0.9, 1.5, -0.2, 0.1, -1.4],
    "debt_su": [-0.9, -0.4, 0.6, 1.3, -0.1, 0.9, -1.2, 1.0, 0.3, 0.2],
    "outcome": ["repaid", "repaid", "default", "default", "repaid",
                "default", "repaid", "default", "repaid", "default"],
})
applicant = np.array([0.0, 0.4])

attributes = loans[['income_su', 'debt_su']]
loans['distance'] = np.sqrt(((attributes - applicant) ** 2).sum(axis=1))
nearest = loans.sort_values('distance')

print("Nearest distance:", round(nearest['distance'].iloc[0], 3))
print("1-NN prediction:", nearest['outcome'].iloc[0])
Nearest distance: 0.141
1-NN prediction: repaid
### Question 2: Majority Vote of 5 Neighbors
#   1. Find the 5 loans nearest to applicant.
#   2. Count the outcomes among them and predict the majority outcome.
# Print exactly:
# Default votes: 3
# Repaid votes: 2
# 5-NN prediction: default
import numpy as np
import pandas as pd

# Past loans; both attributes are already in standard units.
loans = pd.DataFrame({
    "income_su": [1.2, 0.8, -0.3, -1.1, 0.4, -0.9, 1.5, -0.2, 0.1, -1.4],
    "debt_su": [-0.9, -0.4, 0.6, 1.3, -0.1, 0.9, -1.2, 1.0, 0.3, 0.2],
    "outcome": ["repaid", "repaid", "default", "default", "repaid",
                "default", "repaid", "default", "repaid", "default"],
})
applicant = np.array([0.0, 0.4])
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

# Past loans; both attributes are already in standard units.
loans = pd.DataFrame({
    "income_su": [1.2, 0.8, -0.3, -1.1, 0.4, -0.9, 1.5, -0.2, 0.1, -1.4],
    "debt_su": [-0.9, -0.4, 0.6, 1.3, -0.1, 0.9, -1.2, 1.0, 0.3, 0.2],
    "outcome": ["repaid", "repaid", "default", "default", "repaid",
                "default", "repaid", "default", "repaid", "default"],
})
applicant = np.array([0.0, 0.4])

attributes = loans[['income_su', 'debt_su']]
loans['distance'] = np.sqrt(((attributes - applicant) ** 2).sum(axis=1))
votes = loans.sort_values('distance').head(5)['outcome'].value_counts()

print("Default votes:", votes['default'])
print("Repaid votes:", votes['repaid'])
print("5-NN prediction:", votes.idxmax())
# The single nearest loan was repaid, but 3 of the 5 nearest defaulted:
# the choice of k can change the prediction.
Default votes: 3
Repaid votes: 2
5-NN prediction: default
### Question 3: Standardizing a New Case
# The bank's training data are in original units. To compare a new applicant with
# them, convert the applicant to standard units using the TRAINING set's mean and
# SD (np.std, or .std(ddof=0)). Never use the new case to compute the scaling.
#   1. Compute the applicant's income and balance in standard units, each rounded
#      to 2 decimals.
# Print exactly:
# Income in standard units: -0.21
# Balance in standard units: -0.17
import numpy as np
import pandas as pd

training = pd.DataFrame({
    "income": [42, 55, 61, 38, 70, 48],          # $1,000s
    "balance": [1200, 300, 800, 2500, 150, 1900], # $
})
new_applicant = pd.Series({"income": 50, "balance": 1000})
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

training = pd.DataFrame({
    "income": [42, 55, 61, 38, 70, 48],          # $1,000s
    "balance": [1200, 300, 800, 2500, 150, 1900], # $
})
new_applicant = pd.Series({"income": 50, "balance": 1000})

means = training.mean()
sds = training.std(ddof=0)
scaled = (new_applicant - means) / sds

print("Income in standard units:", round(scaled['income'], 2))
print("Balance in standard units:", round(scaled['balance'], 2))
Income in standard units: -0.21
Balance in standard units: -0.17
### Question 4: A Classifier From Start to Finish
#   1. Write classify(training, point, k): compute the distance from point to every
#      row of training (using income_su and debt_su), take the k nearest rows, and
#      return their most common outcome.
#   2. Classify each test loan with k = 3 and print the predictions as a list.
# Print exactly:
# Predictions: ['repaid', 'default', 'default', 'default', 'repaid']
import numpy as np
import pandas as pd

# Past loans; both attributes are already in standard units.
loans = pd.DataFrame({
    "income_su": [1.2, 0.8, -0.3, -1.1, 0.4, -0.9, 1.5, -0.2, 0.1, -1.4],
    "debt_su": [-0.9, -0.4, 0.6, 1.3, -0.1, 0.9, -1.2, 1.0, 0.3, 0.2],
    "outcome": ["repaid", "repaid", "default", "default", "repaid",
                "default", "repaid", "default", "repaid", "default"],
})
test = pd.DataFrame({
    "income_su": [0.9, -0.8, 0.0, -0.5, 0.6],
    "debt_su": [-0.6, 0.8, 0.5, 0.1, 0.4],
    "outcome": ["repaid", "default", "repaid", "repaid", "default"],
})
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

# Past loans; both attributes are already in standard units.
loans = pd.DataFrame({
    "income_su": [1.2, 0.8, -0.3, -1.1, 0.4, -0.9, 1.5, -0.2, 0.1, -1.4],
    "debt_su": [-0.9, -0.4, 0.6, 1.3, -0.1, 0.9, -1.2, 1.0, 0.3, 0.2],
    "outcome": ["repaid", "repaid", "default", "default", "repaid",
                "default", "repaid", "default", "repaid", "default"],
})
test = pd.DataFrame({
    "income_su": [0.9, -0.8, 0.0, -0.5, 0.6],
    "debt_su": [-0.6, 0.8, 0.5, 0.1, 0.4],
    "outcome": ["repaid", "default", "repaid", "repaid", "default"],
})

def classify(training, point, k):
    attributes = training[['income_su', 'debt_su']]
    distances = np.sqrt(((attributes - point) ** 2).sum(axis=1))
    nearest = training.assign(distance=distances).sort_values('distance').head(k)
    return nearest['outcome'].value_counts().idxmax()

predictions = []
for income, debt in zip(test['income_su'], test['debt_su']):
    predictions.append(classify(loans, np.array([income, debt]), 3))
print("Predictions:", predictions)
Predictions: ['repaid', 'default', 'default', 'default', 'repaid']
### Question 5: Test Accuracy
#   1. Using the predictions from Question 4 (given below), compute the accuracy:
#      the proportion of test loans whose prediction matches the actual outcome.
#   2. Compute the accuracy of always predicting "repaid", the more common outcome
#      in the test set, as a baseline.
# Print exactly:
# Classifier accuracy: 0.4
# Baseline accuracy: 0.6
import numpy as np
import pandas as pd

test = pd.DataFrame({
    "outcome": ["repaid", "default", "repaid", "repaid", "default"],
    "predicted": ["repaid", "default", "default", "default", "repaid"],
})
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

test = pd.DataFrame({
    "outcome": ["repaid", "default", "repaid", "repaid", "default"],
    "predicted": ["repaid", "default", "default", "default", "repaid"],
})

accuracy = (test['outcome'] == test['predicted']).mean()
baseline = (test['outcome'] == 'repaid').mean()

print("Classifier accuracy:", accuracy)
print("Baseline accuracy:", baseline)
# On these 5 test loans the classifier does worse than always guessing
# "repaid". With so few test cases, check it on a much larger test set before trusting it.
Classifier accuracy: 0.4
Baseline accuracy: 0.6