Titanic example revisited – all together

In this section, we are going to put all the bits and pieces of feature engineering and dimensionality reduction together:

import re
import numpy as np
import pandas as pd
import random as rd
from sklearn import preprocessing
from sklearn.cluster import KMeans
from sklearn.ensemble import RandomForestRegressor
from sklearn.decomposition import PCA

# Print options
np.set_printoptions(precision=4, threshold=10000, linewidth=160, edgeitems=999, suppress=True)
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
pd.set_option('display.width', 160)
pd.set_option('expand_frame_repr', False)
pd.set_option('precision', 4)


# constructing binary features
def process_embarked():
global df_titanic_data

# replacing the missing values with the most common value in the variable
df_titanic_data.Embarked[df.Embarked.isnull()] = df_titanic_data.Embarked.dropna().mode().values

# converting the values into numbers
df_titanic_data['Embarked'] = pd.factorize(df_titanic_data['Embarked'])[0]

# binarizing the constructed features
if keep_binary:
df_titanic_data = pd.concat([df_titanic_data, pd.get_dummies(df_titanic_data['Embarked']).rename(
columns=lambda x: 'Embarked_' + str(x))], axis=1)



# Define a helper function that can use RandomForestClassifier for handling the missing values of the age variable
def set_missing_ages():
global df_titanic_data

age_data = df_titanic_data[
['Age', 'Embarked', 'Fare', 'Parch', 'SibSp', 'Title_id', 'Pclass', 'Names', 'CabinLetter']]
input_values_RF = age_data.loc[(df_titanic_data.Age.notnull())].values[:, 1::]
target_values_RF = age_data.loc[(df_titanic_data.Age.notnull())].values[:, 0]

# Creating an object from the random forest regression function of sklearn<use the documentation for more details>
regressor = RandomForestRegressor(n_estimators=2000, n_jobs=-1)

# building the model based on the input values and target values above
regressor.fit(input_values_RF, target_values_RF)

# using the trained model to predict the missing values
predicted_ages = regressor.predict(age_data.loc[(df_titanic_data.Age.isnull())].values[:, 1::])

# Filling the predicted ages in the original titanic dataframe
age_data.loc[(age_data.Age.isnull()), 'Age'] = predicted_ages


# Helper function for constructing features from the age variable
def process_age():
global df_titanic_data

# calling the set_missing_ages helper function to use random forest regression for predicting missing values of age
set_missing_ages()

# # scale the age variable by centering it around the mean with a unit variance
# if keep_scaled:
# scaler_preprocessing = preprocessing.StandardScaler()
# df_titanic_data['Age_scaled'] = scaler_preprocessing.fit_transform(df_titanic_data.Age.reshape(-1, 1))

# construct a feature for children
df_titanic_data['isChild'] = np.where(df_titanic_data.Age < 13, 1, 0)

# bin into quartiles and create binary features
df_titanic_data['Age_bin'] = pd.qcut(df_titanic_data['Age'], 4)

if keep_binary:
df_titanic_data = pd.concat(
[df_titanic_data, pd.get_dummies(df_titanic_data['Age_bin']).rename(columns=lambda y: 'Age_' + str(y))],
axis=1)

if keep_bins:
df_titanic_data['Age_bin_id'] = pd.factorize(df_titanic_data['Age_bin'])[0] + 1

if keep_bins and keep_scaled:
scaler_processing = preprocessing.StandardScaler()
df_titanic_data['Age_bin_id_scaled'] = scaler_processing.fit_transform(
df_titanic_data.Age_bin_id.reshape(-1, 1))

if not keep_strings:
df_titanic_data.drop('Age_bin', axis=1, inplace=True)


# Helper function for constructing features from the passengers/crew names
def process_name():
global df_titanic_data

# getting the different names in the names variable
df_titanic_data['Names'] = df_titanic_data['Name'].map(lambda y: len(re.split(' ', y)))

# Getting titles for each person
df_titanic_data['Title'] = df_titanic_data['Name'].map(lambda y: re.compile(", (.*?).").findall(y)[0])

# handling the low occurring titles
df_titanic_data['Title'][df_titanic_data.Title == 'Jonkheer'] = 'Master'
df_titanic_data['Title'][df_titanic_data.Title.isin(['Ms', 'Mlle'])] = 'Miss'
df_titanic_data['Title'][df_titanic_data.Title == 'Mme'] = 'Mrs'
df_titanic_data['Title'][df_titanic_data.Title.isin(['Capt', 'Don', 'Major', 'Col', 'Sir'])] = 'Sir'
df_titanic_data['Title'][df_titanic_data.Title.isin(['Dona', 'Lady', 'the Countess'])] = 'Lady'

# binarizing all the features
if keep_binary:
df_titanic_data = pd.concat(
[df_titanic_data, pd.get_dummies(df_titanic_data['Title']).rename(columns=lambda x: 'Title_' + str(x))],
axis=1)

# scaling
if keep_scaled:
scaler_preprocessing = preprocessing.StandardScaler()
df_titanic_data['Names_scaled'] = scaler_preprocessing.fit_transform(df_titanic_data.Names.reshape(-1, 1))

# binning
if keep_bins:
df_titanic_data['Title_id'] = pd.factorize(df_titanic_data['Title'])[0] + 1

if keep_bins and keep_scaled:
scaler = preprocessing.StandardScaler()
df_titanic_data['Title_id_scaled'] = scaler.fit_transform(df_titanic_data.Title_id.reshape(-1, 1))



# Generate features from the cabin input variable
def process_cabin():
# refering to the global variable that contains the titanic examples
global df_titanic_data

# repllacing the missing value in cabin variable "U0"
df_titanic_data['Cabin'][df_titanic_data.Cabin.isnull()] = 'U0'

# the cabin number is a sequence of of alphanumerical digits, so we are going to create some features
# from the alphabetical part of it
df_titanic_data['CabinLetter'] = df_titanic_data['Cabin'].map(lambda l: get_cabin_letter(l))
df_titanic_data['CabinLetter'] = pd.factorize(df_titanic_data['CabinLetter'])[0]

# binarizing the cabin letters features
if keep_binary:
cletters = pd.get_dummies(df_titanic_data['CabinLetter']).rename(columns=lambda x: 'CabinLetter_' + str(x))
df_titanic_data = pd.concat([df_titanic_data, cletters], axis=1)

# creating features from the numerical side of the cabin
df_titanic_data['CabinNumber'] = df_titanic_data['Cabin'].map(lambda x: get_cabin_num(x)).astype(int) + 1

# scaling the feature
if keep_scaled:
scaler_processing = preprocessing.StandardScaler() # handling the missing values by replacing it with the median feare
df_titanic_data['Fare'][np.isnan(df_titanic_data['Fare'])] = df_titanic_data['Fare'].median()
df_titanic_data['CabinNumber_scaled'] = scaler_processing.fit_transform(df_titanic_data.CabinNumber.reshape(-1, 1))


def get_cabin_letter(cabin_value):
# searching for the letters in the cabin alphanumerical value
letter_match = re.compile("([a-zA-Z]+)").search(cabin_value)

if letter_match:
return letter_match.group()
else:
return 'U'


def get_cabin_num(cabin_value):
# searching for the numbers in the cabin alphanumerical value
number_match = re.compile("([0-9]+)").search(cabin_value)

if number_match:
return number_match.group()
else:
return 0


# helper function for constructing features from the ticket fare variable
def process_fare():
global df_titanic_data

# handling the missing values by replacing it with the median feare
df_titanic_data['Fare'][np.isnan(df_titanic_data['Fare'])] = df_titanic_data['Fare'].median()

# zeros in the fare will cause some division problems so we are going to set them to 1/10th of the lowest fare
df_titanic_data['Fare'][np.where(df_titanic_data['Fare'] == 0)[0]] = df_titanic_data['Fare'][
df_titanic_data['Fare'].nonzero()[
0]].min() / 10

# Binarizing the features by binning them into quantiles
df_titanic_data['Fare_bin'] = pd.qcut(df_titanic_data['Fare'], 4)

if keep_binary:
df_titanic_data = pd.concat(
[df_titanic_data, pd.get_dummies(df_titanic_data['Fare_bin']).rename(columns=lambda x: 'Fare_' + str(x))],
axis=1)

# binning
if keep_bins:
df_titanic_data['Fare_bin_id'] = pd.factorize(df_titanic_data['Fare_bin'])[0] + 1

# scaling the value
if keep_scaled:
scaler_processing = preprocessing.StandardScaler()
df_titanic_data['Fare_scaled'] = scaler_processing.fit_transform(df_titanic_data.Fare.reshape(-1, 1))

if keep_bins and keep_scaled:
scaler_processing = preprocessing.StandardScaler()
df_titanic_data['Fare_bin_id_scaled'] = scaler_processing.fit_transform(
df_titanic_data.Fare_bin_id.reshape(-1, 1))

if not keep_strings:
df_titanic_data.drop('Fare_bin', axis=1, inplace=True)


# Helper function for constructing features from the ticket variable
def process_ticket():
global df_titanic_data

df_titanic_data['TicketPrefix'] = df_titanic_data['Ticket'].map(lambda y: get_ticket_prefix(y.upper()))
df_titanic_data['TicketPrefix'] = df_titanic_data['TicketPrefix'].map(lambda y: re.sub('[.?/?]', '', y))
df_titanic_data['TicketPrefix'] = df_titanic_data['TicketPrefix'].map(lambda y: re.sub('STON', 'SOTON', y))

df_titanic_data['TicketPrefixId'] = pd.factorize(df_titanic_data['TicketPrefix'])[0]

# binarzing features for each ticket layer
if keep_binary:
prefixes = pd.get_dummies(df_titanic_data['TicketPrefix']).rename(columns=lambda y: 'TicketPrefix_' + str(y))
df_titanic_data = pd.concat([df_titanic_data, prefixes], axis=1)

df_titanic_data.drop(['TicketPrefix'], axis=1, inplace=True)

df_titanic_data['TicketNumber'] = df_titanic_data['Ticket'].map(lambda y: get_ticket_num(y))
df_titanic_data['TicketNumberDigits'] = df_titanic_data['TicketNumber'].map(lambda y: len(y)).astype(np.int)
df_titanic_data['TicketNumberStart'] = df_titanic_data['TicketNumber'].map(lambda y: y[0:1]).astype(np.int)

df_titanic_data['TicketNumber'] = df_titanic_data.TicketNumber.astype(np.int)

if keep_scaled:
scaler_processing = preprocessing.StandardScaler()
df_titanic_data['TicketNumber_scaled'] = scaler_processing.fit_transform(
df_titanic_data.TicketNumber.reshape(-1, 1))


def get_ticket_prefix(ticket_value):
# searching for the letters in the ticket alphanumerical value
match_letter = re.compile("([a-zA-Z./]+)").search(ticket_value)
if match_letter:
return match_letter.group()
else:
return 'U'


def get_ticket_num(ticket_value):
# searching for the numbers in the ticket alphanumerical value
match_number = re.compile("([d]+$)").search(ticket_value)
if match_number:
return match_number.group()
else:
return '0'


# constructing features from the passenger class variable
def process_PClass():
global df_titanic_data

# using the most frequent value(mode) to replace the messing value
df_titanic_data.Pclass[df_titanic_data.Pclass.isnull()] = df_titanic_data.Pclass.dropna().mode().values

# binarizing the features
if keep_binary:
df_titanic_data = pd.concat(
[df_titanic_data, pd.get_dummies(df_titanic_data['Pclass']).rename(columns=lambda y: 'Pclass_' + str(y))],
axis=1)

if keep_scaled:
scaler_preprocessing = preprocessing.StandardScaler()
df_titanic_data['Pclass_scaled'] = scaler_preprocessing.fit_transform(df_titanic_data.Pclass.reshape(-1, 1))


# constructing features based on the family variables subh as SibSp and Parch
def process_family():
global df_titanic_data

# ensuring that there's no zeros to use interaction variables
df_titanic_data['SibSp'] = df_titanic_data['SibSp'] + 1
df_titanic_data['Parch'] = df_titanic_data['Parch'] + 1

# scaling
if keep_scaled:
scaler_preprocessing = preprocessing.StandardScaler()
df_titanic_data['SibSp_scaled'] = scaler_preprocessing.fit_transform(df_titanic_data.SibSp.reshape(-1, 1))
df_titanic_data['Parch_scaled'] = scaler_preprocessing.fit_transform(df_titanic_data.Parch.reshape(-1, 1))

# binarizing all the features
if keep_binary:
sibsps_var = pd.get_dummies(df_titanic_data['SibSp']).rename(columns=lambda y: 'SibSp_' + str(y))
parchs_var = pd.get_dummies(df_titanic_data['Parch']).rename(columns=lambda y: 'Parch_' + str(y))
df_titanic_data = pd.concat([df_titanic_data, sibsps_var, parchs_var], axis=1)


# binarzing the sex variable
def process_sex():
global df_titanic_data
df_titanic_data['Gender'] = np.where(df_titanic_data['Sex'] == 'male', 1, 0)


# dropping raw original
def process_drops():
global df_titanic_data
drops = ['Name', 'Names', 'Title', 'Sex', 'SibSp', 'Parch', 'Pclass', 'Embarked',
'Cabin', 'CabinLetter', 'CabinNumber', 'Age', 'Fare', 'Ticket', 'TicketNumber']
string_drops = ['Title', 'Name', 'Cabin', 'Ticket', 'Sex', 'Ticket', 'TicketNumber']
if not keep_raw:
df_titanic_data.drop(drops, axis=1, inplace=True)
elif not keep_strings:
df_titanic_data.drop(string_drops, axis=1, inplace=True)


# handling all the feature engineering tasks
def get_titanic_dataset(binary=False, bins=False, scaled=False, strings=False, raw=True, pca=False, balanced=False):
global keep_binary, keep_bins, keep_scaled, keep_raw, keep_strings, df_titanic_data
keep_binary = binary
keep_bins = bins
keep_scaled = scaled
keep_raw = raw
keep_strings = strings

# reading the train and test sets using pandas
train_data = pd.read_csv('data/train.csv', header=0)
test_data = pd.read_csv('data/test.csv', header=0)

# concatenate the train and test set together for doing the overall feature engineering stuff
df_titanic_data = pd.concat([train_data, test_data])

# removing duplicate indices due to coming the train and test set by re-indexing the data
df_titanic_data.reset_index(inplace=True)

# removing the index column the reset_index() function generates
df_titanic_data.drop('index', axis=1, inplace=True)

# index the columns to be 1-based index
df_titanic_data = df_titanic_data.reindex_axis(train_data.columns, axis=1)

# processing the titanic raw variables using the helper functions that we defined above
process_cabin()
process_ticket()
process_name()
process_fare()
process_embarked()
process_family()
process_sex()
process_PClass()
process_age()
process_drops()

# move the survived column to be the first
columns_list = list(df_titanic_data.columns.values)
columns_list.remove('Survived')
new_col_list = list(['Survived'])
new_col_list.extend(columns_list)
df_titanic_data = df_titanic_data.reindex(columns=new_col_list)

print("Starting with", df_titanic_data.columns.size,
"manually constructing features based on the interaction between them... ", df_titanic_data.columns.values)

# Constructing features manually based on the interaction between the individual features
numeric_features = df_titanic_data.loc[:,
['Age_scaled', 'Fare_scaled', 'Pclass_scaled', 'Parch_scaled', 'SibSp_scaled',
'Names_scaled', 'CabinNumber_scaled', 'Age_bin_id_scaled', 'Fare_bin_id_scaled']]
print(" Using only numeric features for automated feature generation: ", numeric_features.head(10))

new_fields_count = 0
for i in range(0, numeric_features.columns.size - 1):
for j in range(0, numeric_features.columns.size - 1):
if i <= j:
name = str(numeric_features.columns.values[i]) + "*" + str(numeric_features.columns.values[j])
df_titanic_data = pd.concat(
[df_titanic_data, pd.Series(numeric_features.iloc[:, i] * numeric_features.iloc[:, j], name=name)],
axis=1)
new_fields_count += 1
if i < j:
name = str(numeric_features.columns.values[i]) + "+" + str(numeric_features.columns.values[j])
df_titanic_data = pd.concat(
[df_titanic_data, pd.Series(numeric_features.iloc[:, i] + numeric_features.iloc[:, j], name=name)],
axis=1)
new_fields_count += 1
if not i == j:
name = str(numeric_features.columns.values[i]) + "/" + str(numeric_features.columns.values[j])
df_titanic_data = pd.concat(
[df_titanic_data, pd.Series(numeric_features.iloc[:, i] / numeric_features.iloc[:, j], name=name)],
axis=1)
name = str(numeric_features.columns.values[i]) + "-" + str(numeric_features.columns.values[j])
df_titanic_data = pd.concat(
[df_titanic_data, pd.Series(numeric_features.iloc[:, i] - numeric_features.iloc[:, j], name=name)],
axis=1)
new_fields_count += 2

print(" ", new_fields_count, "new features constructed")

# using Spearman correlation method to remove the feature that have high correlation

# calculating the correlation matrix
df_titanic_data_cor = df_titanic_data.drop(['Survived', 'PassengerId'], axis=1).corr(method='spearman')

# creating a mask that will ignore correlated ones
mask_ignore = np.ones(df_titanic_data_cor.columns.size) - np.eye(df_titanic_data_cor.columns.size)
df_titanic_data_cor = mask_ignore * df_titanic_data_cor

features_to_drop = []

# dropping the correclated features
for column in df_titanic_data_cor.columns.values:

# check if we already decided to drop this variable
if np.in1d([column], features_to_drop):
continue

# finding highly correlacted variables
corr_vars = df_titanic_data_cor[abs(df_titanic_data_cor[column]) > 0.98].index
features_to_drop = np.union1d(features_to_drop, corr_vars)

print(" We are going to drop", features_to_drop.shape[0], " which are highly correlated features... ")
df_titanic_data.drop(features_to_drop, axis=1, inplace=True)

# splitting the dataset to train and test and do PCA
train_data = df_titanic_data[:train_data.shape[0]]
test_data = df_titanic_data[test_data.shape[0]:]

if pca:
print("reducing number of variables...")
train_data, test_data = reduce(train_data, test_data)
else:
# drop the empty 'Survived' column for the test set that was created during set concatenation
test_data.drop('Survived', axis=1, inplace=True)

print(" ", train_data.columns.size, "initial features generated... ") # , input_df.columns.values

return train_data, test_data


# reducing the dimensionality for the training and testing set
def reduce(train_data, test_data):
# join the full data together
df_titanic_data = pd.concat([train_data, test_data])
df_titanic_data.reset_index(inplace=True)
df_titanic_data.drop('index', axis=1, inplace=True)
df_titanic_data = df_titanic_data.reindex_axis(train_data.columns, axis=1)

# converting the survived column to series
survived_series = pd.Series(df_titanic_data['Survived'], name='Survived')

print(df_titanic_data.head())

# getting the input and target values
input_values = df_titanic_data.values[:, 1::]
target_values = df_titanic_data.values[:, 0]

print(input_values[0:10])

# minimum variance percentage that should be covered by the reduced number of variables
variance_percentage = .99

# creating PCA object
pca_object = PCA(n_components=variance_percentage)

# trasforming the features
input_values_transformed = pca_object.fit_transform(input_values, target_values)

# creating a datafram for the transformed variables from PCA
pca_df = pd.DataFrame(input_values_transformed)

print(pca_df.shape[1], " reduced components which describe ", str(variance_percentage)[1:], "% of the variance")

# constructing a new dataframe that contains the newly reduced vars of PCA
df_titanic_data = pd.concat([survived_series, pca_df], axis=1)

# split into separate input and test sets again
train_data = df_titanic_data[:train_data.shape[0]]
test_data = df_titanic_data[test_data.shape[0]:]
test_data.reset_index(inplace=True)
test_data.drop('index', axis=1, inplace=True)
test_data.drop('Survived', axis=1, inplace=True)

return train_data, test_data


# Calling the helper functions
if __name__ == '__main__':
train, test = get_titanic_dataset(bins=True, scaled=True, binary=True)
initial_drops = ['PassengerId']
train.drop(initial_drops, axis=1, inplace=True)
test.drop(initial_drops, axis=1, inplace=True)

train, test = reduce(train, test)

print(train.columns.values)
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset