<jupyter_start><jupyter_text><jupyter_code># Import the tools you will need
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Install so the notebook can navigate Kaggle
!pip install kaggle
# Upload your user authentication from your local files
# The user scraped the data himself and I don't have permission to repuload it 
# on github. This is Kaggles solution.
# You have to upload your Kaggle accounts API token to source the dataset
# this link shows how https://www.youtube.com/watch?v=eEgZtNOCJhk&t=82s
# explanation starts at 1:10
# the file should read kaggle.json as default
from google.colab import files
files.upload()
# Direct the notebook to the dataset on kaggle
!mkdir -p ~/.kaggle
!cp kaggle.json ~/.kaggle/

!chmod 600 ~/.kaggle/kaggle.json
# Downloads the zip file from the kaggle website to the notebook
!kaggle datasets download -d kemical/kickstarter-projects
# Seperate the different Excel files into CSVs
!unzip kickstarter-projects.zip
# Take the seperated CSVs and turn them into Pandas dataframes
prj1 = pd.read_csv('ks-projects-201612.csv',header=0,encoding = 'iso-8859-1')
prj2 = pd.read_csv('ks-projects-201801.csv',header=0,encoding = 'iso-8859-1')
# Show the head of each dataframe in order to isloate what
# columns we want in our final dataframe
prj1.head().T
prj2.head().T
# From the prj1 df we do not want 
# the unamed columns, so we drop them
prj1_2 = prj1.drop(prj1.columns[[13,14,15,16]], axis=1)
# Double check
prj1_2.head().T
# From the prj2 df we do not want 
# the redundant columns that could cause leakage, so we drop them
prj2_2 = prj2.drop(prj2.columns[[13,14]], axis=1)
# double check
prj2_2.head().T
# check shapes
print (prj1_2.shape)
prj2_2.shape
# Will work with prj2 for classification
# relabel for convenience
df = prj2_2
# State will be our target
df['state'].value_counts(normalize=True)
# live results will be inconclusive
# cancelled projects have too many extraneous variables around them
# can't draw conclusive evidence from undefined/suspended projects
# will filter these out in favor of a failed/successful binary
df2 = df[(df['state'] != 'canceled') & (df['state'] != 'undefined')
& (df['state'] != 'live') & (df['state'] != 'suspended')]
# double check
df2['state'].value_counts(normalize=True)
# Will want the same split for linear problem
# split begins here
# Classification
# Install the tools
!pip install category_encoders
import category_encoders as ce
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import seaborn as sns
# My majority class frequency is within the range so I will use accuracy as my metric.
# I will test on the sperate dataframe and will use a date/time split to use on my validation split.
df2.head().T
# drop columns that could lead to leakage
df3 = df2.drop(prj2.columns[[8,10,12]], axis=1)
# double check
df3.head().T
# split the train and test set
train = df3[(df3['launched'] < '2017')]
test = df3[(df3['launched'] > '2017')]
print(train.shape)
test.shape
# create validation set
train, val = train_test_split(train, train_size=0.80, test_size=0.20, random_state=42)
target = 'state'
train_features = train.drop(columns=[target])
numeric_features = train_features.select_dtypes(include='number').columns.tolist()
cardinality = train_features.select_dtypes(exclude='number').nunique()
categorical_features = cardinality[cardinality <= 85].index.tolist()
features = numeric_features + categorical_features
X_train = train[features]
y_train = train[target]
X_val = val[features]
y_val = val[target]
X_test = test[features]
y_test = test[target]
from xgboost import XGBClassifier
pipeline = make_pipeline(
    ce.OrdinalEncoder(), 
    XGBClassifier(n_estimators=100, random_state=42, n_jobs=-1)
)

pipeline.fit(X_train, y_train)
pipeline.score(X_val, y_val)
pipeline.score(X_test, y_test)
model = pipeline.named_steps['xgbclassifier']
importances = pd.Series(model.feature_importances_, X_train.columns)

%matplotlib inline
import matplotlib.pyplot as plt

n = 20
plt.figure(figsize=(10,n/2))
plt.title(f'Top {n} features')
importances.sort_values()[-n:].plot.barh(color='blue');
y_pred = pipeline.predict(X_val)
import seaborn as sns
from sklearn.utils.multiclass import unique_labels
unique_labels(y_val)
from sklearn.metrics import confusion_matrix
def plot_confusion_matrix(y_true, y_pred):
    labels = unique_labels(y_true)
    columns = [f'Predicted {label}' for label in labels]
    index = [f'Actual {label}' for label in labels]
    table = pd.DataFrame(confusion_matrix(y_true, y_pred), 
                         columns=columns, index=index)
    return sns.heatmap(table, annot=True, fmt='d', cmap='viridis')

plot_confusion_matrix(y_val, y_pred);
!pip install pdpbox
from pdpbox.pdp import pdp_interact, pdp_interact_plot
from pdpbox.pdp import pdp_isolate, pdp_plot
feature = 'goal'

isolated = pdp_isolate(
    model=pipeline, 
    dataset=X_val, 
    model_features=X_val.columns, 
    feature=feature
)
pdp_plot(isolated, feature_name=feature);
# Linear Model
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression
train2 = df2[(df2['launched'] < '2017')]
test2 = df2[(df2['launched'] > '2017')]
train, val = train_test_split(train2, train_size=0.80, test_size=0.20, random_state=42)
features = ['backers']
target = 'state'
X_train = train2[features]
y_train = train2[target]
X_test = val[features]
y_test = val[target]
model = log_reg(random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
y_pred
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
model.score(X_test, y_test)
plot_confusion_matrix(y_val, y_pred);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10364715860899067, 'fraction_numerical': 0.024597116200169637, 'mean_word_length': 5.684807256235827, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 7, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, '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': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '25115', 'license': 'MIT', 'n_tokens_mistral': 2067, 'n_tokens_neox': 1976, 'n_words': 580, 'path': 'Build_Week_2.ipynb', 'repo_name': 'Cal-0/Cal-0-dashboard.github.io', 'size': '5895'}