How to split pandas dataframe by unique value - python
I am working on implementing an ID3 algorithm in Python. In order to get past the first step I need to calculate the information gain per column. The comments are self-explanatory.
The issue is on the line
# ii) split the given data source based on the
# unique values in the attribute
print(f'split the given data source based on the')
print(f'unique values in the attribute')
df1 = training_set[training_set[columnName] >= k]
df2 = training_set[training_set[columnName] < k]
print("**********")
print("splitting ")
print(f'df1 {df1}')
print(f'df2 {df2}')
print("**********")
The dataframe is imported like so
0 1 2 3 4 5 6 7 8
0 Venue color Model Category Location weight Veriety Material Volume
1 2 6 4 4 4 2 2 1 1
The column names are coming back as numbers. They should be the string value of the headers.
The full program is shown below.
from numpy.core.defchararray import count
import pandas as pd
import numpy as np
import numpy as np
from math import ceil, floor, log2
from sklearn.decomposition import PCA
from numpy import linalg as LA
from sklearn.tree import DecisionTreeClassifier
def calculate_metrics(tp, tn, fn, p, n, fp):
# calculate the accuracy, error rate, sensitivity, specificity, and precision for the selected classifier in reference to the corresponding test set.
accuracy = tp + tn /(p+n)
error_rate = fp + fn /(p + n)
sensitivity = tp/ p
precision = tp/ (tp+fp)
specificity = tn/n
display_metrics(accuracy, error_rate, sensitivity, precision, specificity)
def display_metrics(accuracy, error_rate, sensitivity, precision, specificity):
print(f'Accuracy: {accuracy}, Error_rate:{error_rate}, Sensitivity:{sensitivity}, Precision:{precision}, specificity:{specificity}')
def ID3(threshold,g):
# use the training set to predict the test set.
# use the Assignment 2--Training set to extract rules and test the quality of the extracted rules against the Assignment 2-- Test set for ID3.
test_set = pd.read_csv("Test set for ID3.csv", header=None)
training_set = pd.read_csv("Training set for ID3.csv", header=None)
print(f'test_set: {test_set}')
print(f'training_set: {training_set}')
# Step 1- Calculate MC (Message Conveyed) for the given data set in reference to the class attribute
print(f'Step 1- Calculate MC (Message Conveyed) for the given data set in reference to the class attribute')
# MC = -p1*log2(p1) - p2*log2(p2)
# For n classes MC = -p1log2(p1) - p2*log2(p2)-...-pn*log2(pn)
# For each column calculate the gain.
numberOfColumns = 0
mcDictionary = {}
print('***********************************')
print('For each column calculate the gain.')
for (columnName, columnData) in training_set.iteritems():
print(f'Column Name :{columnName}')
print(f'Column Contents: {training_set[columnName]}')
column = training_set[columnName]
probs = column.value_counts(normalize=True)
print(f'Probability {probs}')
entropy = -1*np.sum(np.log2(probs)*probs)
print(f'Entropy {entropy}')
mcDictionary.update({columnName:round(entropy)})
numberOfColumns+=1
print('***********************************')
print(f'numberOfColumns {numberOfColumns}')
print(f'mcDictionary {mcDictionary}')
# The column with the highest gain is the root.
print(f'The column with the highest gain is the root.')
values = mcDictionary.values()
max_value = max(values)
print(f'The max value is {max_value}')
columnNames = list(mcDictionary.keys())
columnWithMaximumInformationGain = columnNames.index(max_value)
print(f'The max value, {max_value}, is associated with column {columnWithMaximumInformationGain}')
root = training_set[columnWithMaximumInformationGain]
print(f'root {root}')
# Loop
# Step 2 - Repeat for every attribute
print(f'Step 2 - Repeat for every attribute')
for (columnName, columnData) in training_set.iteritems():
# i) use the atttribute as a node from which k
# k branches are emanating, where k is
# the number of unique values in the attribute
attribute = columnName
k = training_set[columnName].nunique()
print(f'use the atttribute {columnName} as a node from which {k}')
print(f'{k} branches are emanating, where {k} is')
print(f'the number of unique values in the attribute')
# ii) split the given data source based on the
# unique values in the attribute
print(f'split the given data source based on the')
print(f'unique values in the attribute')
df1 = training_set[training_set[columnName] >= k]
df2 = training_set[training_set[columnName] < k]
print("**********")
print("splitting ")
print(f'df1 {df1}')
print(f'df2 {df2}')
print("**********")
# iii) calculate MC for new splits
# calculate MC for each attribute of Venue
# iv calculculate the weight for each split
# start with venue
# v) calculate the weighted MC (WMC) for the attribute
# WMC(venue) = W(1)*MC(1) + W(2)*MC(2)
# vi) Calculate Gain for the attribute [MC-WMC(venue)]
# Gain(venue) = MC-WMC(venue)
# Step 3- Repeat for each split produced by the root
# if all records have the same class then break.
# Step 4- If every split is free of a mixture of class values, then stop
# expansion of the tree
# Step 5- Extract rules in form of if-then-else from the tree
# select the max value from the gain array
# this is the new root
# # leaf generated from the decision tree.
# F1 = 0
# # define c1 count of records w/ dominant class in F1
# # How do I determine the number of records w/ dominant class in F1?
# c1 = 0
# # alpha = c1/ |F1|
# # F1 is one of the unique values of a given attribute.
# alpha = c1/ abs(F1)
# # the number of records in the test set that are correctly classified by the rules extracted from the tree before removal.
# # How do I determine the number of records in test set that are correctly classified by rules extracted from the tree before removal?
# N = 0
# # the number of records in the test set that are correctly classified by the rules extracted from the tree.
# # How do I determine the number of records in the test set that are correctly classified by the rules extracted from the tree?
# M = 0
# # the parameter and 0 <= g <= 0.15
# g = 0
# if g < 0 or g > 0.15:
# exit()
# # k is the total number of branches in the subtree
# # How do I determine the total number of branches in the subtree?
# k = 0
# if alpha > threshold:
# # stop splitting tree
# # How do we apply prepruning to the data?
# # For post-pruning use the criteria below
# if (N-M)/Q < g*k:
# # remove subtree
# # true positive
# tp = 0
# # true negative
# tn = 0
# # postive
# p = 0
# # negative
# n = 0
# # false positive
# fp = 0
# calculate_metrics(tp, tn, p, n, fp)
def BayesClassifier():
# use the assignment 2-- training set for Bayes as the training set to classify the records of the assignment 2 test set for bayes
test_set = pd.read_csv("Assignment 2--Test set for Bayes.csv")
training_set = pd.read_csv("Assignment 2--Training set for Bayes.csv")
# prompt user to select either ID3 or Bayes classifier.
selection = "ID3" #= input("Please enter your selection for either ID3 or Bayes classification: ")
threshold = 0.9 #= input("Please enter a threshold: ")
g = 0.5 #= input("Please enter a value for g: ")
if(selection == "ID3"):
ID3(threshold,g)
if(selection == "Bayes"):
BayesClassifier()
Expected:
**********
splitting
df1 {df1}
df2 {df2}
**********
Actual:
unique values in the attribute
Traceback (most recent call last):
File ".\assignment2.py", line 183, in <module>
ID3(threshold,g)
File ".\assignment2.py", line 86, in ID3
df1 = training_set[training_set[columnName] >= k]
File "C:\Users\physe\AppData\Roaming\Python\Python36\site-packages\pandas\core\ops\common.py", line 65, in new_method
return method(self, other)
File "C:\Users\physe\AppData\Roaming\Python\Python36\site-packages\pandas\core\ops\__init__.py", line 370, in wrapper
res_values = comparison_op(lvalues, rvalues, op)
File "C:\Users\physe\AppData\Roaming\Python\Python36\site-packages\pandas\core\ops\array_ops.py", line 244, in comparison_op
res_values = comp_method_OBJECT_ARRAY(op, lvalues, rvalues)
File "C:\Users\physe\AppData\Roaming\Python\Python36\site-packages\pandas\core\ops\array_ops.py", line 56, in comp_method_OBJECT_ARRAY
result = libops.scalar_compare(x.ravel(), y, op)
File "pandas\_libs\ops.pyx", line 103, in pandas._libs.ops.scalar_compare
TypeError: '>=' not supported between instances of 'str' and 'int'
How can I split the dataframe by the unique value?
The Test set for ID3.csv
Venue,color,Model,Category,Location,weight,Veriety,Material,Volume
1,6,4,4,4,1,1,1,6
2,5,4,4,4,2,6,1,1
1,6,2,1,4,1,4,2,4
1,6,2,1,4,1,2,1,2
2,6,5,5,5,2,2,1,2
1,5,4,4,4,1,6,2,2
1,3,3,3,3,1,6,2,2
1,5,2,1,1,1,2,1,2
1,4,4,4,1,1,5,3,6
1,4,4,4,4,1,6,4,6
2,5,4,4,4,2,4,4,1
2,4,3,3,3,2,1,1,1
2,6,5,5,5,1,4,2,1
The Training set for ID3.csv
Venue,color,Model,Category,Location,weight,Veriety,Material,Volume
1,6,4,4,4,1,1,1,6
2,5,4,4,4,2,6,1,1
1,6,2,1,4,1,4,2,4
1,6,2,1,4,1,2,1,2
2,6,5,5,5,2,2,1,2
1,5,4,4,4,1,6,2,2
1,3,3,3,3,1,6,2,2
1,5,2,1,1,1,2,1,2
1,4,4,4,1,1,5,3,6
Don't use header=none
test_set = pd.read_csv("Test set for ID3.csv")
training_set = pd.read_csv("Training set for ID3.csv")
Related
filling the gaps between list of angles (numbers)
i'll explain for simple example then go into the deep if i have a list of number consist of t_original = [180,174,168,166,162,94,70,80,128,131,160,180] if we graph this so it goes down from 180 to 70 then it ups to 180 again but if we suddenly change the fourth value (166) by 450 then the list will be t = [180,174,168,700,162,94,70,80,128,131,160,180] which dose not make sense in the graph i wanna treat the fourth value (700) as a wrong value i want to replace it with a relative value even if not as the original value but relative to the previous two elements (168,174) i wanna do the same for the whole list if another wrong value appeared again we can call that [Filling gaps between list of numbers] so i'm tryig to do the same idea but for bigger example the method i have tried and i'll share my code with output , filtered means applied filling gap function my code def preprocFN(*U): prePlst=[] # after preprocessing list #preprocessing Fc =| 2*LF1 prev by 1 - LF2 prev by 2 | c0 = -2 #(previous) by 2 c1 =-1 #(previous) c2 =0 #(current) c3 = 1 #(next) preP = U[0] # original list if c2 == 0: prePlst.append(preP[0]) prePlst.append(preP[1]) c1+=2 c2+=2 c0+=2 oldlen = len(preP) while oldlen > c2: Equ = abs(2*preP[c1] - preP[c0]) #fn of preprocessing #removed abs() formatted_float = "{:.2f}".format(Equ) #with .2 number only equu = float(formatted_float) #from string float to float prePlst.insert(c2,equu) # insert the preprocessed value to the List c1+=1 c2+=1 c0+=1 return prePlst with my input : https://textuploader.com/t1py9 the output will be : https://textuploader.com/t1pyk and when printing the values higher than 180 (wrong values) result_list = [item for item in list if item > 180] which dosen't make sense that any joint of human can pass the angle of 180 the output was [183.6, 213.85, 221.62, 192.05, 203.39, 197.22, 188.45, 182.48, 180.41, 200.09, 200.67, 198.14, 199.44, 198.45, 200.55, 193.25, 204.19, 204.35, 200.59, 211.4, 180.51, 183.4, 217.91, 218.94, 213.79, 205.62, 221.35, 182.39, 180.62, 183.06, 180.78, 231.09, 227.33, 224.49, 237.02, 212.53, 207.0, 212.92, 182.28, 254.02, 232.49, 224.78, 193.92, 216.0, 184.82, 214.68, 182.04, 181.07, 234.68, 233.63, 182.84, 193.94, 226.8, 223.69, 222.77, 180.67, 184.72, 180.39, 183.99, 186.44, 233.35, 228.02, 195.31, 183.97, 185.26, 182.13, 207.09, 213.21, 238.41, 229.38, 181.57, 211.19, 180.05, 181.47, 199.69, 213.59, 191.99, 194.65, 190.75, 199.93, 221.43, 181.51, 181.42, 180.22] so the filling gaps fn from proposed method dosen't do it's job any suggestion for applying the same concept with a different way ? Extra Info may help the filtered graph consists of filling gap function and then applying normalize function i don't think the problem is from the normalizing function since the output from the filling gaps function isn't correct in my opinion maybe i'm wrong but anyway i provide the normalize steps so you get how the final filtered graph has been made fn : My Code : def outLiersFN(*U): outliers=[] # after preprocessing list #preprocessing Fc =| 2*LF1 prev by 1 - LF2 prev by 2 | c0 = -2 #(previous) by 2 #from original c1 =-1 #(previous) #from original c2 =0 #(current) #from original c3 = 1 #(next) #from original preP = U[0] # original list if c2 == 0: outliers.append(preP[0]) c1+=1 c2+=1 c0+=1 c3+=1 oldlen = len(preP) M_RangeOfMotion = 90 while oldlen > c2 : if c3 == oldlen: outliers.insert(c2, preP[c2]) #preP[c2] >> last element in old list break if (preP[c2] > M_RangeOfMotion and preP[c2] < (preP[c1] + preP[c3])/2) or (preP[c2] < M_RangeOfMotion and preP[c2] > (preP[c1] + preP[c3])/2): #Check Paper 3.3.1 Equ = (preP[c1] + preP[c3])/2 #fn of preprocessing # From third index # ==== inserting current frame formatted_float = "{:.2f}".format(Equ) #with .2 number only equu = float(formatted_float) #from string float to float outliers.insert(c2,equu) # insert the preprocessed value to the List c1+=1 c2+=1 c0+=1 c3+=1 else : Equ = preP[c2] # fn of preprocessing #put same element (do nothing) formatted_float = "{:.2f}".format(Equ) # with .2 number only equu = float(formatted_float) # from string float to float outliers.insert(c2, equu) # insert the preprocessed value to the List c1 += 1 c2 += 1 c0 += 1 c3 += 1 return outliers
I suggest the following algorithm: data point t[i] is considered an outlier if it deviates from the average of t[i-2], t[i-1], t[i], t[i+1], t[i+2] by more than the standard deviation of these 5 elements. outliers are replaced by the average of the two elements around them. import matplotlib.pyplot as plt from statistics import mean, stdev t = [180,174,168,700,162,94,70,80,128,131,160,180] def smooth(t): new_t = [] for i, x in enumerate(t): neighbourhood = t[max(i-2,0): i+3] m = mean(neighbourhood) s = stdev(neighbourhood, xbar=m) if abs(x - m) > s: x = ( t[i - 1 + (i==0)*2] + t[i + 1 - (i+1==len(t))*2] ) / 2 new_t.append(x) return new_t new_t = smooth(t) plt.plot(t) plt.plot(new_t) plt.show()
Trying to Implement Naive Bayes algorithm on dataset
I have a dataset upon which I would like to implement the Naïve Bayes algorithm but it is triggering an error on line 107; str_column_to_float(dataset, i) as follows; "could not convert string to float:''" I thought it was because of the headers for the various columns but even after I removed them and run the code, it is still giving me the same error. Any help will very much be appreciated. The link to the dataset is as follows; [Dataset][1] The code is below # Make Predictions with Naive Bayes On The Accident Project Dataset from csv import reader from math import sqrt from math import exp from math import pi # Load a CSV file def load_csv(filename): dataset = list() with open(filename, 'r') as file: csv_reader = reader(file) for row in csv_reader: if not row: continue dataset.append(row) return dataset # Convert string column to float def str_column_to_float(dataset, column): for row in dataset: row[column] = float(row[column].strip()) # Convert string column to integer def str_column_to_int(dataset, column): class_values = [row[column] for row in dataset] unique = set(class_values) lookup = dict() for i, value in enumerate(unique): lookup[value] = i print('[%s] => %d' % (value, i)) for row in dataset: row[column] = lookup[row[column]] return lookup # Split the dataset by class values, returns a dictionary def separate_by_class(dataset): separated = dict() for i in range(len(dataset)): vector = dataset[i] class_value = vector[-1] if (class_value not in separated): separated[class_value] = list() separated[class_value].append(vector) return separated # Calculate the mean of a list of numbers def mean(numbers): return sum(numbers)/float(len(numbers)) # Calculate the standard deviation of a list of numbers def stdev(numbers): avg = mean(numbers) variance = sum([(x-avg)**2 for x in numbers]) / float(len(numbers)-1) return sqrt(variance) # Calculate the mean, stdev and count for each column in a dataset def summarize_dataset(dataset): summaries = [(mean(column), stdev(column), len(column)) for column in zip(*dataset)] del(summaries[-1]) return summaries # Split dataset by class then calculate statistics for each row def summarize_by_class(dataset): separated = separate_by_class(dataset) summaries = dict() for class_value, rows in separated.items(): summaries[class_value] = summarize_dataset(rows) return summaries # Calculate the Gaussian probability distribution function for x def calculate_probability(x, mean, stdev): exponent = exp(-((x-mean)**2 / (2 * stdev**2 ))) return (1 / (sqrt(2 * pi) * stdev)) * exponent # Calculate the probabilities of predicting each class for a given row def calculate_class_probabilities(summaries, row): total_rows = sum([summaries[label][0][2] for label in summaries]) probabilities = dict() for class_value, class_summaries in summaries.items(): probabilities[class_value] = summaries[class_value][0][2]/float(total_rows) for i in range(len(class_summaries)): mean, stdev, _ = class_summaries[i] probabilities[class_value] *= calculate_probability(row[i], mean, stdev) return probabilities # Predict the class for a given row def predict(summaries, row): probabilities = calculate_class_probabilities(summaries, row) best_label, best_prob = None, -1 for class_value, probability in probabilities.items(): if best_label is None or probability > best_prob: best_prob = probability best_label = class_value return best_label # Make a prediction with Naive Bayes on Accident Dataset filename = 'C:/Users/Vince/Desktop/University of Wyoming PHD/Year 2/Machine Learning/Term Project/Accident Project dataset.csv' dataset = load_csv(filename) for i in range(len(dataset[1])-1): str_column_to_float(dataset, i) # convert class column to integers str_column_to_int(dataset, len(dataset[0])-1) # fit model model = summarize_by_class(dataset) # define a new record row = [1,0,1,0,1,0,1,0,1,0,1,0,1] # predict the label label = predict(model, row) print('Data=%s, Predicted: %s' % (row, label)) [1]: https://docs.google.com/spreadsheets/d/1aFJLSYqo59QUYJ6es09ZHY0UBqwH6cbgV4JjxY1HXZo/edit? usp=sharing
The ValueError is being raised because float() is trying to cast a word to a string. # Raises the ValueError float("one") # Does not raise the ValueError float("1") You need to find the string that is non-numerical and then manually convert it. You can change your code to help you find it, like this: def str_column_to_float(dataset, column): i =0 try: for row in dataset: row[column] = float(row[column].strip()) except ValueError: print(f'Change value: {row[column]} on row {i} column {column} to numeric.') finally: i+=1
NumPy random sampling using larger sample results in less unique elements than smaller sample
I'm trying to build a dataset for training a deep learning model that requires positive and negative sampling. For each input list, I randomly choose 3 elementa to be the positive samplea and k elements to be the negative sample from the rest of the vocabulary. For some reason, at the end, when I use k=16 negative samples for each positive, I get less unique elements than if I would've used k=4 and I'm not sure why that's the case since larger samples should obviously provide more coverage. Here's the code that I have doing the sampling (replace value of num_neg to change # of negatives sampled). I feel like I might be missing something obvious but haven't figured it out... pos_map = {} neg_map = {} num_pos = 3 num_neg = 16 # vocab maps from id => integer index, reverse_map maps from integer index => id. vocab size is ~28k and stores all possible values of id np.random.seed(2) for ids in ids_list: encoded = [vocab[id_] for id_ in ids] target_positive_indices = np.random.choice(range(len(encoded)), size=num_pos, replace=False) for target_positive_index in target_positive_indices: pos = encoded[target_positive_index] if pos in pos_map: pos_map[pos] += 1 else: pos_map[pos] = 1 # perform negative sampling all_indices = np.arange(vocab_size) possible_negs = np.random.choice(range(len(all_indices)), size=num_neg * 3, replace=False) # some negatives chosen could be the same as positives or in the context, filter those out filtered_negs = np.setdiff1d(possible_negs, store_indexes)[:num_neg] for n in filtered_negs: neg = reverse_map[n] if neg in neg_map: neg_map[neg] += 1 else: neg_map[neg] = 1 print(len(neg_map)) Result for num_neg=4: 15842 Result for num_neg=16: 13968
Numpy Array Manipulation Based off of Internal Values
I am trying to accomplish a weird task. I need to complete the following without the use of sklearn, and preferably with numpy: Given a dataset, split the data into 5 equal "folds", or partitions Within each partition, split the data into a "training" and "testing" set, with an 80/20 split Here is the catch: Your dataset is labeled for classes. So take for example a dataset with 100 instances, and class A with 33 samples and class B with 67 samples. I should create 5 folds of 20 data instances, where in each fold, class A has something like 6 or 7 (1/3) values and class B has the rest My issue that: I do not know how to properly return a test and training set for each fold, despite being able to split it appropriately, and, more important, I do not know how to incorporate the proper division of # of elements per class. My current code is here. It is commented where I am stuck: import numpy def csv_to_array(file): # Open the file, and load it in delimiting on the ',' for a comma separated value file data = open(file, 'r') data = numpy.loadtxt(data, delimiter=',') # Loop through the data in the array for index in range(len(data)): # Utilize a try catch to try and convert to float, if it can't convert to float, converts to 0 try: data[index] = [float(x) for x in data[index]] except Exception: data[index] = 0 except ValueError: data[index] = 0 # Return the now type-formatted data return data def five_cross_fold_validation(dataset): # print("DATASET", dataset) numpy.random.shuffle(dataset) num_rows = dataset.shape[0] split_mark = int(num_rows / 5) folds = [] temp1 = dataset[:split_mark] # print("TEMP1", temp1) temp2 = dataset[split_mark:split_mark*2] # print("TEMP2", temp2) temp3 = dataset[split_mark*2:split_mark*3] # print("TEMP3", temp3) temp4 = dataset[split_mark*3:split_mark*4] # print("TEMP4", temp4) temp5 = dataset[split_mark*4:] # print("TEMP5", temp5) folds.append(temp1) folds.append(temp2) folds.append(temp3) folds.append(temp4) folds.append(temp5) # folds = numpy.asarray(folds) for fold in folds: # fold = numpy.asarray(fold) num_rows = fold.shape[0] split_mark = int(num_rows * .8) fold_training = fold[split_mark:] fold_testing = fold[:split_mark] print(type(fold)) # fold.tolist() list(fold) print(type(fold)) del fold[0:len(fold)] fold.append(fold_training) fold.append(fold_testing) fold = numpy.asarray(fold) # Somehow, return a testing and training set within each fold # print(folds) return folds def confirm_size(folds): total = 0 for fold in folds: curr = len(fold) total = total + curr return total def main(): print("BEGINNING CFV") ecoli = csv_to_array('Classification/ecoli.csv') print(len(ecoli)) folds = five_cross_fold_validation(ecoli) size = confirm_size(folds) print(size) main() Additionally, for reference, I have attached my csv I am working with (it is a modification of the UCI Ecoli Dataset.) The classes here are the values in the last column. So 0, 1, 2, 3, 4. It is important to note that there are not equal amounts of each class. 0.61,0.45,0.48,0.5,0.48,0.35,0.41,0 0.17,0.38,0.48,0.5,0.45,0.42,0.5,0 0.44,0.35,0.48,0.5,0.55,0.55,0.61,0 0.43,0.4,0.48,0.5,0.39,0.28,0.39,0 0.42,0.35,0.48,0.5,0.58,0.15,0.27,0 0.23,0.33,0.48,0.5,0.43,0.33,0.43,0 0.37,0.52,0.48,0.5,0.42,0.42,0.36,0 0.29,0.3,0.48,0.5,0.45,0.03,0.17,0 0.22,0.36,0.48,0.5,0.35,0.39,0.47,0 0.23,0.58,0.48,0.5,0.37,0.53,0.59,0 0.47,0.47,0.48,0.5,0.22,0.16,0.26,0 0.54,0.47,0.48,0.5,0.28,0.33,0.42,0 0.51,0.37,0.48,0.5,0.35,0.36,0.45,0 0.4,0.35,0.48,0.5,0.45,0.33,0.42,0 0.44,0.34,0.48,0.5,0.3,0.33,0.43,0 0.44,0.49,0.48,0.5,0.39,0.38,0.4,0 0.43,0.32,0.48,0.5,0.33,0.45,0.52,0 0.49,0.43,0.48,0.5,0.49,0.3,0.4,0 0.47,0.28,0.48,0.5,0.56,0.2,0.25,0 0.32,0.33,0.48,0.5,0.6,0.06,0.2,0 0.34,0.35,0.48,0.5,0.51,0.49,0.56,0 0.35,0.34,0.48,0.5,0.46,0.3,0.27,0 0.38,0.3,0.48,0.5,0.43,0.29,0.39,0 0.38,0.44,0.48,0.5,0.43,0.2,0.31,0 0.41,0.51,0.48,0.5,0.58,0.2,0.31,0 0.34,0.42,0.48,0.5,0.41,0.34,0.43,0 0.51,0.49,0.48,0.5,0.53,0.14,0.26,0 0.25,0.51,0.48,0.5,0.37,0.42,0.5,0 0.29,0.28,0.48,0.5,0.5,0.42,0.5,0 0.25,0.26,0.48,0.5,0.39,0.32,0.42,0 0.24,0.41,0.48,0.5,0.49,0.23,0.34,0 0.17,0.39,0.48,0.5,0.53,0.3,0.39,0 0.04,0.31,0.48,0.5,0.41,0.29,0.39,0 0.61,0.36,0.48,0.5,0.49,0.35,0.44,0 0.34,0.51,0.48,0.5,0.44,0.37,0.46,0 0.28,0.33,0.48,0.5,0.45,0.22,0.33,0 0.4,0.46,0.48,0.5,0.42,0.35,0.44,0 0.23,0.34,0.48,0.5,0.43,0.26,0.37,0 0.37,0.44,0.48,0.5,0.42,0.39,0.47,0 0,0.38,0.48,0.5,0.42,0.48,0.55,0 0.39,0.31,0.48,0.5,0.38,0.34,0.43,0 0.3,0.44,0.48,0.5,0.49,0.22,0.33,0 0.27,0.3,0.48,0.5,0.71,0.28,0.39,0 0.17,0.52,0.48,0.5,0.49,0.37,0.46,0 0.36,0.42,0.48,0.5,0.53,0.32,0.41,0 0.3,0.37,0.48,0.5,0.43,0.18,0.3,0 0.26,0.4,0.48,0.5,0.36,0.26,0.37,0 0.4,0.41,0.48,0.5,0.55,0.22,0.33,0 0.22,0.34,0.48,0.5,0.42,0.29,0.39,0 0.44,0.35,0.48,0.5,0.44,0.52,0.59,0 0.27,0.42,0.48,0.5,0.37,0.38,0.43,0 0.16,0.43,0.48,0.5,0.54,0.27,0.37,0 0.06,0.61,0.48,0.5,0.49,0.92,0.37,1 0.44,0.52,0.48,0.5,0.43,0.47,0.54,1 0.63,0.47,0.48,0.5,0.51,0.82,0.84,1 0.23,0.48,0.48,0.5,0.59,0.88,0.89,1 0.34,0.49,0.48,0.5,0.58,0.85,0.8,1 0.43,0.4,0.48,0.5,0.58,0.75,0.78,1 0.46,0.61,0.48,0.5,0.48,0.86,0.87,1 0.27,0.35,0.48,0.5,0.51,0.77,0.79,1
Edit I replaced np.random.shuffle(A) by A = np.random.permutation(A), the only difference is that it doesn't mutate the input array. This doesn't make any difference in this code, but it is safer in general. The idea is to randomly sample the input by using numpy.random.permutation. Once the rows are shuffled we just need to iterate over all the possible tests sets (sliding window of the desired size, here 20% of the input size). The corresponding training sets are just composed of all remaining elements. This will preserve the original classes distribution on all subsets even though we pick them in order because we shuffled the input. The following code iterate over the test/train sets combinations: import numpy as np def csv_to_array(file): with open(file, 'r') as f: data = np.loadtxt(f, delimiter=',') return data def classes_distribution(A): """Print the class distributions of array A.""" nb_classes = np.unique(A[:,-1]).shape[0] total_size = A.shape[0] for i in range(nb_classes): class_size = sum(row[-1] == i for row in A) class_p = class_size/total_size print(f"\t P(class_{i}) = {class_p:.3f}") def random_samples(A, test_set_p=0.2): """Split the input array A in two uniformly chosen random sets: test/training. Repeat this until all rows have been yielded once at least once as a test set.""" A = np.random.permutation(A) sample_size = int(test_set_p*A.shape[0]) for start in range(0, A.shape[0], sample_size): end = start + sample_size yield { "test": A[start:end,], "train": np.append(A[:start,], A[end:,], 0) } def main(): ecoli = csv_to_array('ecoli.csv') print("Input set shape: ", ecoli.shape) print("Input set class distribution:") classes_distribution(ecoli) print("Training sets class distributions:") for iteration in random_samples(ecoli): test_set = iteration["test"] training_set = iteration["train"] classes_distribution(training_set) print("---") # ... Do what ever with these two sets main() It produces an output of the form: Input set shape: (169, 8) Input set class distribution: P(class_0) = 0.308 P(class_1) = 0.213 P(class_2) = 0.207 P(class_3) = 0.118 P(class_4) = 0.154 Training sets class distributions: P(class_0) = 0.316 P(class_1) = 0.206 P(class_2) = 0.199 P(class_3) = 0.118 P(class_4) = 0.162 ...
How to add a stopping condition for Jacobian Matrix?
def jacobi(m,numiter=100): #Number of rows determins the number of variables numvars = m.shape[0] #construct array for final iterations history = np.zeros((numvars,numiter)) i = 1 while(i < numiter): #Loop for numiter for v in range(numvars): # Loop over all variables current = m[v,numvars] # Start with left hand side (augmented side of matrix) for col in range(numvars): #Loop over columns if v != col: # Don't count colume for current variable current = current - (m[v,col]*history[col, i-1]) #subtract other guesses form previous timestep current = current/m[v,v] #divide by current variable coefficent history[v,i] = current #Add this answer to the rest i = i + 1 #iterate #plot each variable for v in range(numvars): plt.plot(history[v,: i]); return history[:,i-1] I have this code that calculates Jacobian method. How do I add a stopping condition for when the solutions converge? i.e. the values for the current iteration have changed less than some threshold e from the values for the previous iteration. The threshold e will be an input to the function and the default value to 0.00001
You could add another condition to your while loop, so when it reaches your error threshold it stops. def jacobi(m,numiter=100, error_threshold = 1e-4): #Number of rows determins the number of variables numvars = m.shape[0] #construct array for final iterations history = np.zeros((numvars,numiter)) i = 1 err = 10*error_threshold while(i < numiter and err > error_threshold): #Loop for numiter and error threshold for v in range(numvars): # Loop over all variables current = m[v,numvars] # Start with left hand side (augmented side of matrix) for col in range(numvars): #Loop over columns if v != col: # Don't count colume for current variable current = current - (m[v,col]*history[col, i-1]) #subtract other guesses form previous timestep current = current/m[v,v] #divide by current variable coefficent history[v,i] = current #Add this answer to the rest #check error here. In this case the maximum error if i > 1: err = max((history[:,i] - history[:,i-1])/history[:,i-1]) i = i + 1 #iterate #plot each variable for v in range(numvars): plt.plot(history[v,: i]); return history[:,i-1]