Skip to main content
1 of 2

Stratified Sampling/Naive Bayesian C++

(I was brought here from stackexchange.com)

For my project, I'm required to create three training datasets from a set of about 45000 elements (32000 after cleaning incomplete elements). Each line looks like this:

38, Private, 215646, HS-grad, 9, Divorced, Handlers-cleaners, Not-in-family, White, Male, 0, 0, 40, United-States, <=50K

I'm supposed to sample them with stratified sampling and I believe my implementation is correct, however it is quite slow since it takes over 30 secs to finish just the stratified sampling part.

After that, I have to pick out 20 random data points in each testing dataset (for each training set) and implement my naive bayesian classifier on each one to determine if it's a positive value (ie, the salary is > 50k) or a negative (ie, the salary is <= 50k.

My implementation is here. Basically im asking how can I pretty up the code to make it run faster when stratify sampling it.

Also, how in god's name do I classify using Naive Bayesian? I'm thinking for each point I randomly chose from the testing dataset, for each attribute, I find the number of matching points that have that attribute value in the training dataset. Then count all points with that value that succeed and then count the ones that fail. Then compute probability for that class. After I do it for each attribute, I multiply the probabilities together and see which one is closer to the probability of failure or probability of failure. Then see if my guess matches the actual result.

#include <iostream> //std::cout
#include <fstream> //std::ifstream
#include <string> //std::string
#include <sstream> //std::istringstream
#include <vector> //std::vector
#include <algorithm> //std::remove
#include <ctime> //std::time

struct Person{
    int age;
    std::string workclass;
    int fnlwgt;
    std::string education;
    int educationNum;
    std::string maritalStatus;
    std::string occupation;
    std::string relationship;
    std::string race;
    std::string sex;
    int capitalGain;
    int capitalLoss;
    int hoursPerWeek;
    std::string nativeCountry;
    std::string salary;
};

std::vector<Person> testData;

//Prints data of single person
void printPerson(Person person){
    std::cout << person.age << " " << person.workclass << 
        " " << person.fnlwgt << " " << person.education << 
        " " << person.educationNum << " " << person.maritalStatus <<
        " " << person.occupation << " " << person.relationship <<
        " " << person.race << " " << person.sex << 
        " " << person.capitalGain << " " << person.capitalLoss << 
        " " << person.hoursPerWeek << " " << person.nativeCountry <<
        std::endl;
}

//Converts int to string
std::string convertInt(int x){
    std::string result;
    std::ostringstream convert;
    
    convert << x;
    result = convert.str();
    return result;
}

//Generates
int randNumGenerator(int max){
    int num = (rand() % max);
    //std::cout << num << std::endl;
    return num;
}

//Sets up all persons in data set with complete values
void setData(Person person, std::string line){
        
        line.erase(std::remove(line.begin(), line.end(), ','), line.end());
        
        std::stringstream s(line);
        std::string str;
        
        //Nominal attributes
        std::string workclass;
        std::string education;
        std::string maritalStatus;
        std::string occupation;
        std::string relationship;
        std::string race;
        std::string sex;
        std::string nativeCountry;
        
        //class label
        std::string salary;
        
        //Continuous attributes
        int age;
        std::string ageStr;
        
        
        int fnlwgt;
        std::string fnlwgtStr;

        int educationNum;
        std::string educationNumStr;

        int capitalGain;
        std::string capitalGainStr;
        
        int capitalLoss;
        std::string capitalLossStr;
        
        int hoursPerWeek;
        std::string hoursPerWeekStr;
        
        //Read in values into stringstream
        if(s >> age >> workclass >> fnlwgt >> education >> educationNum >>
            maritalStatus >> occupation >> relationship >> race >> sex >> capitalGain >>
            capitalLoss >> hoursPerWeek >> nativeCountry >> salary){
                
                //Convert ints into strings
                ageStr = convertInt(age);
                fnlwgtStr = convertInt(fnlwgt);
                educationNumStr = convertInt(educationNum);
                capitalGainStr = convertInt(capitalGain);
                capitalLossStr = convertInt(capitalLoss);
                hoursPerWeekStr = convertInt(hoursPerWeek);
                
                //Check if values are missing
                if(ageStr == "?" || workclass == "?" ||
                    fnlwgtStr == "?" || education == "?" || 
                    educationNumStr == "?" || maritalStatus == "?" ||
                    occupation == "?" || relationship == "?" ||
                    race== "?" || sex == "?" || 
                    capitalGainStr == "?" || capitalLossStr == "?" ||
                    hoursPerWeekStr == "?" || nativeCountry == "?"){
                        
                }
                else{
                    person.age = age;
                    person.workclass = workclass;
                    person.fnlwgt = fnlwgt;
                    person.education = education;
                    person.educationNum = educationNum;
                    person.maritalStatus = maritalStatus;
                    person.occupation = occupation;
                    person.relationship = relationship;
                    person.race = race;
                    person.sex = sex;
                    person.capitalGain = capitalGain;
                    person.capitalLoss = capitalLoss;
                    person.hoursPerWeek = hoursPerWeek;
                    person.nativeCountry = nativeCountry;
                    person.salary = salary;
                    testData.push_back(person);
                }
        }
        
        //printPerson(person);
}

//Sets up strata for positive values
std::vector<Person> setPositive(std::vector<Person> data){
    for(int i = 0; i < testData.size(); i++){
        if(testData[i].salary == ">50K"){
            data.push_back(testData[i]);
        }
    }
    return data;
}

//Sets up strata for negative values
std::vector<Person> setNegative(std::vector<Person> data){
    for(int i = 0; i < testData.size(); i++){
        if(testData[i].salary == "<=50K"){
            data.push_back(testData[i]);
        }
    }
    return data;
}

std::vector<Person> sample(std::vector<Person> &wholeDataSet, int percentage){
    int wholeDataSize = wholeDataSet.size();
    
    std::vector<Person> stratifiedSet;
    
    int limit = (wholeDataSize * percentage) / 100;
    
    int randNum= 0;
    
    std::vector<bool> numsUsedAlready(wholeDataSize);

    for(int i = 0; i < limit; i++){
        randNum = randNumGenerator(wholeDataSize);
        while(numsUsedAlready[randNum]){
            randNum = randNumGenerator(wholeDataSize);
        }
        numsUsedAlready[randNum] = true;
        stratifiedSet.push_back(wholeDataSet[randNum]); 
        wholeDataSet.erase(wholeDataSet.begin() + randNum);
        //std::cout << i << std::endl;
    } 
    
    //delete numsUsedAlready
    return stratifiedSet;
}

std::vector<Person> concatVectors(std::vector<Person> a, std::vector<Person> b){
    std::vector<Person> ab;
    ab.reserve(a.size() + b.size());
    ab.insert(ab.end(), a.begin(), a.end()); //Add a
    ab.insert(ab.end(), b.begin(), b.end()); //Add b
    return ab;
}

bool classifier(Person person){
    
}

float naiveBayesian(std::vector<Person> trainingSet, std::vector<Person> testingSet){
    float accuracy = 0;
    int randNum = 0;
    
    std::vector<Person> sampleSet;
    std::vector<bool> numsUsedAlready(testingSet.size());
    
    for(int i = 0; i < 20; i++){
        randNum = randNumGenerator(testingSet.size());
        while(numsUsedAlready[randNum]){
            randNum = randNumGenerator(testingSet.size());
        }
        numsUsedAlready[randNum] = true;
        sampleSet.push_back(testingSet[randNum]);
    }
    
    float ageProb;
    float workclassProb;
    float fnlwgtProb;
    float educationProb;
    float educationNumProb;
    std::string maritalStatus;
    std::string occupation;
    std::string relationship;
    std::string race;
    std::string sex;
    int capitalGain;
    int capitalLoss;
    int hoursPerWeek;
    std::string nativeCountry;
    std::string salary;
    
    
    bool salaryGreaterThan50k = false;
    for(int i = 0; i < sampleSet.size(); i++){
        //salaryGreaterThan50k = classifier(sampleSet[i]);
    }
    
    return accuracy;
}

void stratifiedSample(){
    srand(time(NULL)); 
    
    std::vector<Person> positiveSamples;
    std::vector<Person> negativeSamples;
    positiveSamples = setPositive(positiveSamples);
    negativeSamples = setNegative(negativeSamples);
    
    std::vector<Person> posTestingSet10 = positiveSamples;
    std::vector<Person> posTestingSet30 = positiveSamples;
    std::vector<Person> posTestingSet50 = positiveSamples;
    
    std::vector<Person> negTestingSet10 = negativeSamples;
    std::vector<Person> negTestingSet30 = negativeSamples;
    std::vector<Person> negTestingSet50 = negativeSamples;
    
    std::vector<Person> posStratifiedSet_10;
    std::vector<Person> posTesting_10;
    std::vector<Person> negStratifiedSet_10;
    
    std::vector<Person> posStratifiedSet_30;
    std::vector<Person> negStratifiedSet_30;
    
    std::vector<Person> posStratifiedSet_50;
    std::vector<Person> negStratifiedSet_50;
    
    std::vector<Person> stratifiedSet_10;
    std::vector<Person> stratifiedSet_30;
    std::vector<Person> stratifiedSet_50;
    
    std::vector<Person> testingSet_10;
    std::vector<Person> testingSet_30;
    std::vector<Person> testingSet_50;
    

    posStratifiedSet_10 = sample(posTestingSet10, 10);
    //std::cout << "size of stratified " << posStratifiedSet_10.size() << " size of testing set10 " << posTestingSet10.size() << std::endl;
    
    negStratifiedSet_10 = sample(negTestingSet10, 10);
    std::cout << "Done w/ 10" << std::endl;
    
    posStratifiedSet_30 = sample(posTestingSet30, 30);
    negStratifiedSet_30 = sample(negTestingSet30, 30);
    std::cout << "Done w/ 30" << std::endl;
    
    posStratifiedSet_50 = sample(posTestingSet50, 50);
    negStratifiedSet_50 = sample(negTestingSet50, 50);
    std::cout << "Done w/ 50" << std::endl;

    stratifiedSet_10 = concatVectors(posStratifiedSet_10, negStratifiedSet_10);
    stratifiedSet_30 = concatVectors(posStratifiedSet_30, negStratifiedSet_30);
    stratifiedSet_50 = concatVectors(posStratifiedSet_50, negStratifiedSet_50);
    
    testingSet_10 = concatVectors(posTestingSet10, negTestingSet10);
    testingSet_30 = concatVectors(posTestingSet30, negTestingSet30);
    testingSet_50 = concatVectors(posTestingSet50, negTestingSet50);

    //std::cout << "size10: " << stratifiedSet_10.size() << " testingSet10: " << testingSet_10.size() << std::endl;
    float accuracy10 = 0;
    float accuracy30 = 0;
    float accuracy50 = 0;
    
    accuracy10 = naiveBayesian(stratifiedSet_10, testingSet_10);
 

}

//Reads the file
void readInputFile(std::ifstream &file){
    std::string line;
    while(getline(file,line)){
        Person person;
        setData(person, line);
    }
}

//Prints the usage string
void usageString(){
    std::cout << "Usage: myProgram.exe <input_file>" << std::endl;
}


int main(int argc, char** argv){
    const char *inputfile;
    
    if (argc < 2){
        usageString();
        return EXIT_FAILURE;
    }
    else{
        inputfile = argv[1];
    }
    
    std::ifstream input(inputfile);
    if(!input.is_open()){
        std::cerr << "Error: Data file doesn't exist" << std::endl;
        return EXIT_FAILURE;
    }
    
    readInputFile(input);
    stratifiedSample();
    return 1;
}