<jupyter_start><jupyter_text>Loading Data* Load the data* Split features from predictor class* Encode features* Filter outliers<jupyter_code>raw_data = pd.read_csv('data/house-votes-84.data.txt', names=['party'] + ['v%02d'%x for x in range(16)])
raw_data.head()
# Split the data into party affiliation (output variable) and votes (features)
party = raw_data['party']
votes = raw_data.drop('party', axis=1)
print(f'# Entries {raw_data.shape[0]}, # Features {raw_data.shape[1]-1}')
print(f'\nClass distribution: \n{party.value_counts()}')
print(f'\nFeature distribution: \n{pd.Series(votes.values.flatten()).value_counts()}')
# Map the votes to easy to process feature values
features = votes.apply(lambda x: x.map({'n':0, '?':1, 'y':2}), axis=1)
features.head()
voting_treshold = 4

# Filter votes, that have than half of missing votes (keep those that have less than 8 missing votes)
nmissing_votes = (features == 1).sum(axis=1)
keep = nmissing_votes <= voting_treshold

print(f'Dropping {keep.shape[0] - keep.sum()} rows because to more than {voting_treshold} missing votes!')

party = party[keep]
votes = votes[keep]
features = features[keep]<jupyter_output>Dropping 14 rows because to more than 4 missing votes!<jupyter_text>Handle missing valuesTwo datasets will be generated, using two different methods to handle the missing data* Process each vote/column seperatly and fill entries based on the most common value of the 5 closest neighbours. Neighbours are calculated has most similar encoding.* Random selection of yes or no votes<jupyter_code>def nn_fill(table, N=5, missing_value=0):
    # Store results here
    cleaned = table.copy()

    for column_idx in range(table.shape[1]):

        has_missing = (table.iloc[:, column_idx] == missing_value)
        print(f'Found #{has_missing.sum()} missing valuesin column {column_idx}. Start filling them ...')

        missing = table[has_missing].drop(table.columns[column_idx], axis=1)
        # Get all neighbours, dropping the column that needs prediction
        neighbours = table[~has_missing].drop(table.columns[column_idx], axis=1)

        # For each missing, calculate its neighbour distance
        for i, s in missing.iterrows():
            # Calculate the distance as the absolute numeric difference
            distance = neighbours.apply(lambda x: abs(x - s).sum(), axis=1)

            # Find the most common value among the N closest neighbours
            most_common = table.loc[distance.sort_values()[0:N].index, table.columns[column_idx]].mode().values[0]

            #print(f'for row {i} we found the most common value to be {most_common}')
            cleaned.loc[i, table.columns[column_idx]] = most_common

    print('All done!')
    
    return cleaned

def random_fill(table, seed=42, missing_value=0, values=[-1, 1]):
    # Initalize random generator
    np.random.seed(seed)
    
    # Which rows and colums need filling
    missing_r, missing_col = np.where(features.values == missing_value)
    
    # Generate some random sequence
    rand_idx = np.random.randint(0, len(values), size=missing_r.size)

    # Store result here
    random_fill = features.copy()
    for vote, row, column in zip(rand_idx, missing_r, missing_col):
        random_fill.iloc[row, column] = values[vote]
        
    return random_fill
# Number of nearest neighbours to use
cleaned_features = nn_fill(features, N=5, missing_value=1)
random_features = random_fill(features, seed=8888, missing_value=1, values=[0, 2])<jupyter_output>Found #5 missing valuesin column 0. Start filling them ...
Found #39 missing valuesin column 1. Start filling them ...
Found #6 missing valuesin column 2. Start filling them ...
Found #6 missing valuesin column 3. Start filling them ...
Found #10 missing valuesin column 4. Start filling them ...
Found #6 missing valuesin column 5. Start filling them ...
Found #8 missing valuesin column 6. Start filling them ...
Found #8 missing valuesin column 7. Start filling them ...
Found #18 missing valuesin column 8. Start filling them ...
Found #3 missing valuesin column 9. Start filling them ...
Found #11 missing valuesin column 10. Start filling them ...
Found #22 missing valuesin column 11. Start filling them ...
Found #18 missing valuesin column 12. Start filling them ...
Found #10 missing valuesin column 13. Start filling them ...
Found #20 missing valuesin column 14. Start filling them ...
Found #92 missing valuesin column 15. Start filling them ...
All done!<jupyter_text>Building a classifier* Split data into training and test set* Train a Naive Bayes Classifier with bernoulli distribution<jupyter_code>from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import BernoulliNB
from sklearn.naive_bayes import GaussianNB
from sklearn.naive_bayes import MultinomialNB

# Use 20% for testing
training_test_ratio = 0.2

train_idx, test_idx = train_test_split(party.index, test_size=training_test_ratio, random_state=1001)
# Train classifier
data = cleaned_features
#data = random_features

clf = BernoulliNB().fit(data.loc[train_idx], party.loc[train_idx])
# Perform prediction
prediction = clf.predict(data.loc[test_idx])
truth = party.loc[test_idx].values<jupyter_output><empty_output><jupyter_text>Evaluate prediction quality<jupyter_code>from sklearn.metrics import confusion_matrix
import seaborn as sns
sns.set()
labels = ['democrat', 'republican']
mat = confusion_matrix(truth, prediction)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,
            xticklabels=labels, yticklabels=labels)
plt.xlabel('true label')
plt.ylabel('predicted label');
plt.show()
accurracy = (mat[0, 0] + mat[1, 1]) / mat.sum()
print(f'Accuracy {accurracy*100.0:2.0f}%')<jupyter_output>Accuracy 91%<jupyter_text>Cross ValidationUse cross validation with a 5 fold to estimate accuracy, comparing the different variations of classifiers, and data sets.<jupyter_code>from sklearn.model_selection import cross_val_score

F = 5 

nn_scores_b = cross_val_score(BernoulliNB(), cleaned_features, party, cv=F)
rand_scores_b = cross_val_score(BernoulliNB(), random_features, party, cv=F)

nn_scores_g = cross_val_score(GaussianNB(), cleaned_features, party, cv=F)
rand_scores_g = cross_val_score(GaussianNB(), random_features, party, cv=F)

nn_scores_m = cross_val_score(MultinomialNB(), cleaned_features, party, cv=F)
rand_scores_m = cross_val_score(MultinomialNB(), random_features, party, cv=F)

scores = [nn_scores_b, rand_scores_b, nn_scores_g, rand_scores_g, nn_scores_m, rand_scores_m]
scores_labels = ['NN - Bernoulli', 'Random - Bernoulli', 'NN - Gausian', 'Random - Gausian', 'NN - MultiN', 'Random - MultiN']
# Plot cross validation result
fig, axs = plt.subplots(1, 1, figsize=(10, 7))
bp = axs.boxplot(scores, 0, labels=scores_labels, positions=range(len(scores)))
for i, sv in enumerate(scores):
    axs.scatter([i]*len(sv), sv)
axs.set_ylim(0.5, 1.0)
axs.set_xlabel('Classifiers')
axs.set_ylabel('Accuracy')
axs.set_title('Cross validation comparison')
plt.show()
for sn, sv in zip(scores_labels, scores):
    print(f'{sn}: mean {sv.mean():2.3f}, var {sv.var():2.3f}')<jupyter_output>NN - Bernoulli: mean 0.905, var 0.002
Random - Bernoulli: mean 0.905, var 0.001
NN - Gausian: mean 0.940, var 0.001
Random - Gausian: mean 0.943, var 0.001
NN - MultiN: mean 0.907, var 0.002
Random - MultiN: mean 0.907, var 0.002
{'fraction_non_alphanumeric': 0.11414965986394558, 'fraction_numerical': 0.024081632653061225, 'mean_word_length': 4.797318611987381, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '461413', 'license': 'MIT', 'n_tokens_mistral': 2499, 'n_tokens_neox': 2322, 'n_words': 715, 'path': 'Aprendizaje_Automatica/Actividades/T1/.ipynb_checkpoints/T1-Manuel_Pasieka-checkpoint.ipynb', 'repo_name': 'mapa17/UNIR-IA', 'size': '7350'}