This script shows a minimum working example for the feat2vec library. feat2vec learns dense vectors for all types of features used in data science- categories, real-valued variables, even images or text. It is an answer to word2vec's widespread usage for vector representation of things that are not really words. It can group "similar columns" into single features that have a more sensible interpretation (for example, a 10-dimensional matrix indicating what genres a movie might belong to can be aggregated to a single "genre" embedding). We use Factorization Machines and a novel sampling algorithm to generate these data. Please see the PDF in the repo for detailed technical explanation of our learning method.
It is built primarily on pandas, numpy, and keras. Below we show a minimum working example
import numpy as np
import pandas as pd
import tensorflow as tf
import keras
import deepfm
from deepfm import DeepFM
import implicitsampler
reload(implicitsampler)
from implicitsampler import ImplicitSampler
Set some important hyperparameters
np.random.seed(1)
samplesize = 100000 #number of records
batch_size=2000 #number of positive labels per batch
neg_samples=5 #number of negative labels per batch
embed_dim = 10 #dimensionality of embeddings to learn
Generate some fake data in a pandas df, including a latent variable that generates a binary variable to create a correlation structure
attrs = np.random.multivariate_normal(mean = np.array([0.,0.]), cov = np.array([[1.,.1],[.1,1]]),size=samplesize)
data = pd.DataFrame({ 'item': np.random.randint(0,10,size=samplesize),
'id': np.random.randint(0,50,size=samplesize),
'attr1':attrs[:,0],
'attr2':attrs[:,1],
'attr3': np.random.uniform(size=samplesize),
'offset_':np.zeros(samplesize)
})
data['latenty'] = ( (data.attr3)**4/600. + np.exp(data.attr1*data.attr2) \
+ (data.item<=3)*np.pi - ((data.item==2) | (data.item==4))*data.attr3 \
+ ((data.item==8) | (data.item==7) )*data.attr2 \
+ (data.item>=6)*data.attr1 + (data.id%3)*data.attr3 \
+ np.random.normal(size=samplesize) - 5 )
data.loc[np.abs(data['latenty']) >= 10,'latenty'] = 0
data['y'] = np.floor(data.latenty)
Define what features we are going to use and how we are going to use them Some important things to note here:
- Each item in the model_features list will be represented as a dense vector that learns similarities by interacting with all other model features
- Each item in the sampling_features list represents a unique feature of data that should be sampled together for the oversampling method . For example, one might want to sample car model and car manufacturer together because other combinations are not only not observed in the data, they are entirely nonsensical. sampling_features do not need to coincide with model features (i.e. a researcher might still feel its important to learn separate embeddings for make and model of a car)
- features is a list of what we call the model_features in the keras model layers
- We pass most arguments to feat2vec as a list of lists, and often each sub-list only has one element. this is necessary because it is possible to have multiple elements in a single "feature"
- We aggregate attr1,attr2,attr3 into a single "feature" called attrs. The idea is these features all represent at a high level one characteristic of each observation, and so should be grouped together. One might imagine in a real world setting, instead aggregating city,county,state columns into a single "location" feature vector.
features = ['item','id','attrs','y','offset']
model_features = [['item'],['id'],['attr1','attr2','attr3'],['y'],['offset_']]
sampling_features = model_features
Define how we are going to use the features in the model; specifically, whether to learn biases or embeddings only. typically, we want do not want to learn bias terms since these are not straightforward to import to external applications. Here we only learn embeddings for everything except the intercept term (offset_) which we keep to modify the average level of the score function. both bias_only and embeddings_only except an ordered boolean list where positionally they correspond to each feature listed in model_features
also pass a realvalued bool list which tells our model whether we should treat the inputs as discrete categories or real-valued scalar numbers
finally, feature_dims refers to the dimensionality of each feature. for discrete categories, this is the total # of categories. for realvalued features, this is the number of columns (i.e. for attrs it is 3)
bias_only = [False]*len(model_features)
bias_only[ features.index('offset') ] =True
embeddings_only = [True]*len(model_features)
embeddings_only[ features.index('offset') ] =False
realvalued = [False]*len(model_features)
realvalued[ features.index('attrs') ] =True
feature_dims = [10,50,3,2,1]
build the feat2vec model in keras; note we specify noise contrastive estimation as the objective; negative sampling is also available but disencouraged
feat2vec_obj = DeepFM(feature_dims, embed_dim, obj='nce' ,
feature_names=features,realval=realvalued)
feat2vec_fm = feat2vec_obj.build_model(deep_out=False,bias_only=bias_only,embeddings_only=embeddings_only)
print feat2vec_fm.summary()
shallow
____________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
====================================================================================================
item (InputLayer) (None, 1) 0
____________________________________________________________________________________________________
id (InputLayer) (None, 1) 0
____________________________________________________________________________________________________
y (InputLayer) (None, 1) 0
____________________________________________________________________________________________________
embedding_item (Embedding) (None, 1, 10) 100 item[0][0]
____________________________________________________________________________________________________
embedding_id (Embedding) (None, 1, 10) 500 id[0][0]
____________________________________________________________________________________________________
attrs (InputLayer) (None, 3) 0
____________________________________________________________________________________________________
embedding_y (Embedding) (None, 1, 10) 20 y[0][0]
____________________________________________________________________________________________________
offset (InputLayer) (None, 1) 0
____________________________________________________________________________________________________
factor_item_reshaped (Reshape) (None, 10) 0 embedding_item[0][0]
____________________________________________________________________________________________________
factor_id_reshaped (Reshape) (None, 10) 0 embedding_id[0][0]
____________________________________________________________________________________________________
factor_attrs (Dense) (None, 10) 30 attrs[0][0]
____________________________________________________________________________________________________
factor_y_reshaped (Reshape) (None, 10) 0 embedding_y[0][0]
____________________________________________________________________________________________________
bias_offset (Embedding) (None, 1, 1) 1 offset[0][0]
____________________________________________________________________________________________________
interaction_itemXid (Dot) (None, 1) 0 factor_item_reshaped[0][0]
factor_id_reshaped[0][0]
____________________________________________________________________________________________________
interaction_itemXattrs (Dot) (None, 1) 0 factor_item_reshaped[0][0]
factor_attrs[0][0]
____________________________________________________________________________________________________
interaction_itemXy (Dot) (None, 1) 0 factor_item_reshaped[0][0]
factor_y_reshaped[0][0]
____________________________________________________________________________________________________
interaction_idXattrs (Dot) (None, 1) 0 factor_id_reshaped[0][0]
factor_attrs[0][0]
____________________________________________________________________________________________________
interaction_idXy (Dot) (None, 1) 0 factor_id_reshaped[0][0]
factor_y_reshaped[0][0]
____________________________________________________________________________________________________
interaction_attrsXy (Dot) (None, 1) 0 factor_attrs[0][0]
factor_y_reshaped[0][0]
____________________________________________________________________________________________________
bias_offset_reshaped (Reshape) (None, 1) 0 bias_offset[0][0]
____________________________________________________________________________________________________
factors_term (Add) (None, 1) 0 interaction_itemXid[0][0]
interaction_itemXattrs[0][0]
interaction_itemXy[0][0]
interaction_idXattrs[0][0]
interaction_idXy[0][0]
interaction_attrsXy[0][0]
____________________________________________________________________________________________________
output_layer (Add) (None, 1) 0 bias_offset_reshaped[0][0]
factors_term[0][0]
____________________________________________________________________________________________________
noise_probs (InputLayer) (None, 1) 0
____________________________________________________________________________________________________
nce_obj (Lambda) (None, 1) 0 output_layer[0][0]
noise_probs[0][0]
====================================================================================================
Total params: 651
Trainable params: 651
Non-trainable params: 0
____________________________________________________________________________________________________
None
create the probabilities for step1 of our sampler which determines how likely a feature is resampled for producing a negative label. here we choose
Pr(choose feature
where
step1_probs = implicitsampler.gen_step1_probs(feat2vec_fm,features,.5)
--Original Probs--
[ 0.15384615 0.76923077 0.04615385 0.03076923 0. ]
--New Probs with alpha=0.5--
[ 0.23635051 0.52849582 0.12945451 0.10569916 0. ]
Split data into validation and training data
pct_train = .90
train_sample = np.random.uniform(size=samplesize)
train_sample = (train_sample <=np.percentile(train_sample,pct_train*100) ).astype('bool')
train_data = data[train_sample==True]
valid_data = data[train_sample==False]
Create samplers from implicitsampler class . Here we pass the second main hyperparameter,
-
sampling_bias adds a minimum count to each unique value in the data to ensure very low frequency values get sampled enough
-
negative_samples is the number of negative samples per observed record
-
keep_noise_probs necessary if we use NCE, otherwise should not use.
trainsampler = ImplicitSampler(train_data,model_features=model_features,sampling_features=sampling_features,
batch_size=batch_size,
sampling_alpha=.25,sampling_bias=10,
negative_samples=neg_samples,
init_probs = step1_probs,keep_noise_probs=feat2vec_obj.obj=='nce')
validsampler = ImplicitSampler(valid_data,model_features=model_features,sampling_features=sampling_features,
batch_size=batch_size,
sampling_alpha=.25,sampling_bias=10,
negative_samples=neg_samples,
init_probs = step1_probs,keep_noise_probs=feat2vec_obj.obj=='nce')
no sampling_items passed; generating unique item sets from df passed
[['item'], ['id'], ['attr1', 'attr2', 'attr3'], ['y'], ['offset_']]
generating probs for ['item']
generating probs for ['id']
generating probs for ['attr1', 'attr2', 'attr3']
generating probs for ['y']
generating probs for ['offset_']
calculating prob lookup dict for expedited sampling of negative labels...
no sampling_items passed; generating unique item sets from df passed
[['item'], ['id'], ['attr1', 'attr2', 'attr3'], ['y'], ['offset_']]
generating probs for ['item']
generating probs for ['id']
generating probs for ['attr1', 'attr2', 'attr3']
generating probs for ['y']
generating probs for ['offset_']
calculating prob lookup dict for expedited sampling of negative labels...
Finally, fit the model!
callbacks = [keras.callbacks.EarlyStopping(monitor='val_loss', patience=0)]
feat2vec_fm.compile(loss='binary_crossentropy', metrics=['accuracy'], optimizer=keras.optimizers.TFOptimizer(tf.train.AdamOptimizer()))
feat2vec_fm.fit_generator(generator = trainsampler.keras_generator(),
epochs=100,
steps_per_epoch = len(train_data)/batch_size,
validation_data=validsampler.keras_generator(),
validation_steps = len(valid_data)/batch_size,
callbacks=callbacks,
verbose=1,
max_queue_size=1,
workers=1,
use_multiprocessing=True)
Epoch 1/100
45/45 [==============================] - 2s - loss: 2.5072 - acc: 0.1667 - val_loss: 2.2352 - val_acc: 0.1667�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 2/100
45/45 [==============================] - 2s - loss: 2.4291 - acc: 0.1667 - val_loss: 2.1263 - val_acc: 0.1667����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 3/100
45/45 [==============================] - 2s - loss: 2.3014 - acc: 0.1667 - val_loss: 1.9676 - val_acc: 0.1670����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 4/100
45/45 [==============================] - 2s - loss: 2.1383 - acc: 0.1971 - val_loss: 1.7576 - val_acc: 0.2735���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 5/100
45/45 [==============================] - 2s - loss: 1.9130 - acc: 0.3305 - val_loss: 1.5434 - val_acc: 0.3594�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 6/100
45/45 [==============================] - 2s - loss: 1.6586 - acc: 0.3707 - val_loss: 1.3196 - val_acc: 0.3949����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 7/100
45/45 [==============================] - 2s - loss: 1.4672 - acc: 0.4243 - val_loss: 1.1340 - val_acc: 0.4838�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 8/100
45/45 [==============================] - 2s - loss: 1.3114 - acc: 0.6036 - val_loss: 1.0048 - val_acc: 0.7237�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 9/100
45/45 [==============================] - 2s - loss: 1.2051 - acc: 0.7437 - val_loss: 0.9449 - val_acc: 0.7448����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 10/100
45/45 [==============================] - 2s - loss: 1.1436 - acc: 0.7472 - val_loss: 0.8915 - val_acc: 0.7459����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 11/100
45/45 [==============================] - 2s - loss: 1.1083 - acc: 0.7466 - val_loss: 0.8676 - val_acc: 0.7443���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 12/100
45/45 [==============================] - 2s - loss: 1.0901 - acc: 0.7458 - val_loss: 0.8320 - val_acc: 0.7483�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 13/100
45/45 [==============================] - 2s - loss: 1.0600 - acc: 0.7479 - val_loss: 0.8172 - val_acc: 0.7500�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Epoch 14/100
45/45 [==============================] - 2s - loss: 1.0572 - acc: 0.7469 - val_loss: 0.8272 - val_acc: 0.7450���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
<keras.callbacks.History at 0x7f33f27b9750>
#collect embeddings
embeddings = []
embed_names = ['dim_'+str(i) for i in range(1,embed_dim+1)]
for j in feat2vec_obj.feature_names:
for l in feat2vec_fm.layers:
if l.name=='factor_{}'.format(j) or l.name=='embedding_{}'.format(j):
embedding = feat2vec_fm.get_layer(l.name).get_weights()[0]
embedding = pd.DataFrame(embedding,columns=embed_names)
embedding['value'] = [j +'_' + str(i) for i in embedding.index]
embeddings.append(embedding)
embeddings = pd.concat(embeddings,ignore_index=True)
def kNN_embeddings(value,k):
embedding = embeddings.loc[embeddings['value']==value,embed_names]
scores = np.dot(embeddings[embed_names],embedding.T).flatten()
scores = np.array([s/(np.linalg.norm(embedding)*np.linalg.norm(embeddings.loc[i,embed_names])) for i,s in enumerate(scores)]).flatten()
temp = np.argsort(-scores)
ranks = np.empty(len(scores), int)
ranks[temp] = np.arange(len(scores))
for r in range(1,k+1):
print embeddings.loc[ranks==r,'value'].values,scores[ranks==r]
kNN_embeddings('y_1',5)
['y_0'] [ 0.99250478]
['attrs_0'] [ 0.55079764]
['id_36'] [ 0.496499]
['id_4'] [ 0.48362786]
['id_14'] [ 0.48132333]