I have a set of objects, each of which can have (but doesn't always exhibit) a set of properties. Properties are shared between objects, in the sense that different objects can have common properties but the sets of possible properties of any two different objects cannot be identical. The data looks like this:
Property,Object
property1,object1
property2,object1
property2,object2
property3,object1
property3,object3
property4,object2
There are some 1,200 properties and a couple of hundred objects. The number of properties that objects can exhibit is not constant - e.g., object1 has 3 properties in the example above, object 2 has 2 properties, while object 3 has only 1.
I would like to train a ML model that takes a list of observed properties and lists the 10 objects that are the most likely to have been observed, along with some kind of number, expressing the confidence of the recognition.
Problem is, I'm very new to ML and have no idea how to do this.
To begin with, I think I should use a naive Bayes classifier. Since the properties are binary (an object either has a property, or it does not), I think that I should use a Bernoulli naive Bayes classifier. Is this correct?
Then, I have a problem figuring out how to encode the data. Since it is categorical instead of numerical ("property1", etc. instead of a number), I need to encode it somehow. The most obvious way seems to be LabelEncoder
- but then the model might attach meaning to how different the numbers are from each other, while in reality the properties are not related this way. It is my understanding that the way to resolve this is by using the OneHotEncoder
. Is this correct? And, if I do, given that there are some 1,200 properties, this would result in a huge sparse matrix. Wouldn't that be a problem? Or maybe I should use something else?
Furthermore, I do not understand how to convert this data into something usable by BernoulliNB
. It is my understanding that it takes two arguments - an array of vectors, each vector containing the properties of an object, and a vector of objects. I have grouped the data by objects (not sure if I'm doing it properly - I mean, the result seems fine but maybe there is a better way to do it) but BernoulliNB
still refuses to accept the data.
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.naive_bayes import BernoulliNB
data = read_csv('data.csv')
encoded_data = data.copy()
encoder = LabelEncoder()
encoded_data['Property'] = encoder.fit_transform(data['Property'].to_numpy())
encoded_data['Object'] = encoder.fit_transform(data['Object'].to_numpy())
grouped = encoded_data.groupby('Object')
x = []
for name, group in grouped:
x.append(list(group['Property'].to_numpy()))
y = list(encoded_data['Object'].to_numpy())
model = BernoulliNB()
model.fit(x, y)
I get an error that the input data is in the wrong format. Any suggestions how to do this properly? Do the vectors of the array that is the first argument have to have the same length? If yes, how do I achieve this, given that the different objects can have a different number of properties?
I am stuck at this point but once I get past this it, I have more questions that I don't know how to answer. Once I train the model, I want to use it with future data. Obviously, I need to save the trained model somehow, and then load it, so that I don't need to re-train it every time I run the program. One way to do it is with pickle
. What do I save this way? The variable model
? Or whatever model.fit(x, y)
returns? Or something else?
Again talking about applying the trained model to future data - the future data will again arrive in categorical form, so will need to be encoded too. How do I make sure that it is encoded exactly the same way as the data used to train the model?
Finally, it is my understanding that the model produces a single answer - in my case, the object that is the closest match to the observed properties. I can measure the confidence of this answer. But how do I make it produce a list of the 10 closest matching objects, each with its own confinece measurement?