Machine Learning for user modelling

I have a dataset where each row is a interaction of a user with a content. I have user's features to represent the user (each user is uniquely represented through user.id):

user.id, user.nationality, user.company, user.role

and content's feature:

content.id, content.type, content.activity..


My goal is to use ML techniques to predict a content (given by a user.id). My main problem is that, for a new prediction, I have the features of the user, but I do not have the features of the new content.

• Do you have training data, i.e. pairs of user.id and content.id that go together? – Bruno Lubascher Jul 17 '18 at 12:04
• @BrunoGL yes! i have – lgndrzzz Jul 17 '18 at 12:18
• @gdlzzzz I wouldn't include contentid (or userid) as features. Are you basically doing a recommender based on Content Filtering? In that case you pass the new content features against each user feature set to see which users have a high chance of interacting with it. – Ken Syme Jul 17 '18 at 12:45
• @gdlzzzz is 1) your set of contents fixed, so given a new user, you want to choose which content from the existing pool of contents would be best for him. Or 2) for every new user, you create a completely new content just for him? – Bruno Lubascher Jul 17 '18 at 14:00
• @BrunoGL 1) my contents is fixed. – lgndrzzz Jul 17 '18 at 14:24

What you have is a classification problem. Given a user and their features, pick the best content for him.

There are many classifiers that are for this task. I would say that your main problem is that most of your features are categorical and not numerical.

Data preparation

With Sklearn for example, you can use LabelEncoder to transform categorical to numerical.

Below is an example of how to do this. You generate X, which is your features matrix. Each row is a user and the columns are the features.

Here are some dummy users I created. You data structure might be different, so you can try to make it like this, or do some more work on it.

users = [
{
'id': 1,
'nationality': 'american',
'company': 'xyz',
'role': 'ceo',
'content.id': 1001
},
{
'id': 2,
'nationality': 'american',
'company': 'abc',
'role': 'cto',
'content.id': 1002
},
{
'id': 3,
'company': 'fgh',
'role': 'cto',
'content.id': 1001
}
]


Now, you can encode your categories. This means that for every word in your data, you assign a number to it. The LabelEncoder can do this for you. With this, you generate X, which is your feature matrix, where every row represents a user.

from sklearn.preprocessing import LabelEncoder

nationality_encoder = LabelEncoder().fit([user['nationality'] for user in users])
company_encoder = LabelEncoder().fit([user['company'] for user in users])
role_encoder = LabelEncoder().fit([user['role'] for user in users])

X = []
for user in users:
X.append([
nationality_encoder.transform([user['nationality']])[0],
company_encoder.transform([user['company']])[0],
role_encoder.transform([user['role']])[0]
])
print(X)
>> [[0, 2, 0],
>>  [0, 0, 1],
>>  [1, 1, 1]]


Then you can generate y, which are your labels. The content.id of each user. Here I assume you have the user-content pairs like you said you did. This vector has the same length as X. Each row of X is associate to the ordered values in y. So the user in X[2] has the content.id in y[2].

y = [user['content.id'] for user in users]
print(y)
>> [1001, 1002, 1001]


Classifier

Now you have your X and y, your features and labels.

Not all classifier will perform well with categorical data, but I would suggest you start with a DecisionTreeClassifier.

Here is an example:

from sklearn.tree import DecisionTreeClassifier

decision_tree = DecisionTreeClassifier()
decision_tree.fit(X, y)


New predictions

Now that you have a trained tree, you can predict the content.id for users that do not have it.

Suppose you have this new user:

new_user = {
'id': 999,
'nationality': 'american',
'company': 'fgh',
'role': 'ceo'
}


You can apply the same transformation to get the X for him. However, now you do not know y, which is what you are trying to find out.

new_user_X = [[
nationality_encoder.transform([new_user['nationality']])[0],
company_encoder.transform([new_user['company']])[0],
role_encoder.transform([new_user['role']])[0]
]]


Use the decision_tree you created to make a prediction. In this dummy example, the new_user should have content.id == 1.

new_user_content = decision_tree.predict(new_user_X)
print(new_user_content)
>> [1]