"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
""
],
"text/plain": [
""
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# code for loading the format for the notebook\n",
"import os\n",
"\n",
"# path : store the current path to convert back to it later\n",
"path = os.getcwd()\n",
"os.chdir(os.path.join('..', '..', 'notebook_format'))\n",
"from formats import load_style\n",
"load_style(css_style = 'custom2.css', plot_style = False)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ethen 2018-02-24 20:09:44 \n",
"\n",
"CPython 3.6.3\n",
"IPython 6.1.0\n",
"\n",
"numba 0.37.0\n",
"numpy 1.14.1\n",
"pandas 0.22.0\n",
"sklearn 0.19.1\n",
"matplotlib 2.1.0\n"
]
}
],
"source": [
"os.chdir(path)\n",
"\n",
"# 1. magic for inline plot\n",
"# 2. magic to print version\n",
"# 3. magic so that the notebook will reload external python modules\n",
"# 4. magic to enable retina (high resolution) plots\n",
"# https://gist.github.com/minrk/3301035\n",
"%matplotlib inline\n",
"%load_ext watermark\n",
"%load_ext autoreload\n",
"%autoreload 2\n",
"%config InlineBackend.figure_format = 'retina'\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"from sklearn.metrics import roc_auc_score\n",
"from sklearn.linear_model import LogisticRegression\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"\n",
"%watermark -a 'Ethen' -d -t -v -p numba,numpy,pandas,sklearn,matplotlib"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Factorization Machine (FM)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Factorization Machine** type algorithms are a combination of linear regression and matrix factorization, the cool idea behind this type of algorithm is it aims model interactions between features (a.k.a attributes, explanatory variables) using factorized parameters. By doing so it has the ability to estimate all interactions between features even with extremely sparse data."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Introduction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Normally, when we think of linear regression, we would think of the following formula:\n",
"\n",
"\\begin{align}\n",
"\\hat{y}(\\textbf{x}) = w_{0} + \\sum_{i=1}^{n} w_{i} x_{i}\n",
"\\end{align}\n",
"\n",
"Where:\n",
"\n",
"- $w_0$ is the bias term, a.k.a intercept.\n",
"- $w_i$ are weights corresponding to each feature vector $x_i$, here we assume we have $n$ total features.\n",
"\n",
"This formula's advantage is that it can computed in linear time, $O(n)$. The drawback, however, is that it does not handle feature interactions. To capture interactions, we could introduce a weight for each feature combination. This is sometimes referred to as a $2_{nd}$ ordered polynomial. The resulting model is shown below:\n",
"\n",
"\\begin{align}\n",
"\\hat{y}(\\textbf{x}) = w_{0} + \\sum_{i=1}^{n} w_{i} x_{i} + \\sum_{i=1}^n \\sum_{j=i+1}^n w_{ij} x_{i} x_{j}\n",
"\\end{align}\n",
"\n",
"Compared to our previous model, this formulation has the advantages that it can capture feature interactions at least for two features at a time. But we have now ended up with a $O(n^2)$ complexity which means that to train the model, we now require a lot more time and memory. Another issue is that when we have categorical variables with high cardinality, after one-hot encoding them, we would end up with a lot of columns that are sparse, making it harder to actually capture their interactions (not enough data).\n",
"\n",
"To solve this complexity issue, Factorization Machines takes inspiration from [matrix factorization](http://nbviewer.jupyter.org/github/ethen8181/machine-learning/blob/master/recsys/1_ALSWR.ipynb), and models the feature interaction using latent factors. Every feature $f_i$ has a corresponding latent factor $v_i$, and two features' interactions are modelled as $\\langle \\textbf{v}_i, \\textbf{v}_{j} \\rangle$, where $\\langle \\cdot \\;,\\cdot \\rangle$ refers to the dot product of the two feature vector. If we assume its of size $k$ (this is a hyperparameter that we can tune). Then:\n",
"\n",
"\\begin{align}\n",
"\\langle \\textbf{v}_i, \\textbf{v}_{j} \\rangle = \\sum_{f=1}^k v_{i,f} v_{j,f}\n",
"\\end{align}\n",
"\n",
"This leads of our new equation:\n",
"\n",
"\\begin{align}\n",
"\\hat{y}(\\textbf{x}) = w_{0} + \\sum_{i=1}^{n} w_{i} x_{i} + \\sum_{i=1}^{n} \\sum_{j=i+1}^n \\langle \\textbf{v}_i , \\textbf{v}_{j} \\rangle x_i x_{j}\n",
"\\end{align}\n",
"\n",
"This is an improvement from our previous model (when we modeled each pair of interaction terms with weight $w_{ij}$) as the number of parameters is reduced from $n^2$ to $n \\times k$, since $k \\ll n$, which also helps mitigate overfitting issues. Using the naive way of formulating factorization machine results in a complexity of $O(kn^2)$, because all pairwise interactions have to be computed, but we can reformulate it to make it run in $O(kn)$.\n",
"\n",
"\n",
"\\begin{align}\n",
"\\sum_{i=1}^n \\sum_{j=i+1}^n \\langle \\textbf{v}_i, \\textbf{v}_{j} \\rangle x_{i} x_{j}\n",
"&= \\frac{1}{2} \\sum_{i=1}^n \\sum_{j=1}^n \\langle \\textbf{v}_i, \\textbf{v}_{j} \\rangle x_{i} x_{j} - \\frac{1}{2} \\sum_{i=1}^n \\langle \\textbf{v}_i , \\textbf{v}_{i} \\rangle x_{i} x_{i} \\\\\n",
"&= \\frac{1}{2}\\left(\\sum_{i=1}^n \\sum_{j=1}^n \\sum_{f=1}^k v_{i,f} v_{j,f} x_{i} x_{j} \\right) - \\frac{1}{2}\\left( \\sum_{i=1}^n \\sum_{f=1}^k v_{i,f} v_{i,f} x_{i} x_{i} \\right) \\\\\n",
"&= \\frac{1}{2}\\left(\\sum_{i=1}^n \\sum_{j=1}^n \\sum_{f=1}^k v_{i,f} v_{j,f} x_{i} x_{j} - \\sum_{i=1}^n \\sum_{f=1}^k v_{i,f} v_{i,f} x_{i} x_{i} \\right) \\\\\n",
"&= \\frac{1}{2} \\sum_{f=1}^{k} \\left( \\left(\\sum_{i=1}^n v_{i,f}x_{i} \\right) \\left( \\sum_{j=1}^n v_{j,f}x_{j} \\right) - \\sum_{i=1}^{n} v_{i,f}^2 x_{i}^2 \\right) \\\\\n",
"&= \\frac{1}{2} \\sum_{f=1}^{k} \\left( \\left( \\sum_{i}^{n} v_{i,f}x_{i} \\right)^2 - \\sum_{i=1}^{n} v_{i,f}^2 x_{i}^2 \\right)\n",
"\\end{align}\n",
"\n",
"Note, summing over different pairs is the same as summing over all pairs minus the self-interactions (divided by two). This is the reason why the value 1/2 is introduced from the beginning of the derivation.\n",
"\n",
"This reformulated equation has a linear complexity in both $k$ and $n$, i.e. its computation is in $O(kn)$, substituting this new equation into the existing factorization machine formula, we end up with:\n",
"\n",
"\\begin{align}\n",
"\\hat{y}(\\textbf{x}) = w_{0} + \\sum_{i=1}^{n} w_{i} x_{i} + \\frac{1}{2} \\sum_{f=1}^{k} \\left( \\left( \\sum_{i}^{n} v_{i,f}x_{i} \\right)^2 - \\sum_{i=1}^{n} v_{i,f}^2 x_{i}^2 \\right)\n",
"\\end{align}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In a machine learning setting, factorization machine can be applied to different supervised prediction tasks:\n",
"\n",
"- **Regression:**, in this case $\\hat{y}(\\textbf{x})$ can be used directly by minimizing the mean squared error between the model prediction and target value, e.g. $\\frac{1}{N}\\sum^{N}\\big(y - \\hat{y}(\\textbf{x})\\big)^2$\n",
"- **Classification:**, if we were to use it in a binary classification setting, we could then minimize the log loss, $\\ln \\big(e^{-y \\cdot \\hat{y}(\\textbf{x})} + 1 \\big)$, where $\\sigma$ is the sigmoid/logistic function and $y \\in {-1, 1}$.\n",
"\n",
"To train factorization machine, we can use a gradient descent based optimization techniques, the parameters to be learned are $(w_0, \\mathbf{w},$ and $\\mathbf{V}$).\n",
"\n",
"\\begin{align}\n",
"\\frac{\\partial}{\\partial\\theta}\\hat{y}(\\textbf{x}) =\n",
"\\begin{cases}\n",
"1, & \\text{if $\\theta$ is $w_0$} \\\\\n",
"x_i, & \\text{if $\\theta$ is $w_i$} \\\\\n",
"x_i\\sum_{j=1}^{n} v_{j,f}x_j - v_{i,f}x_{i}^2 & \\text{if $\\theta$ is $v_{i,f}$}\n",
"\\end{cases}\n",
"\\end{align}\n",
"\n",
"- Notice that $\\sum_{j=1}^n v_{j, f} x_j$ does not depend on $i$, thus it can be computed independently.\n",
"- The last formula above, can also be written as $x_i(\\sum_{j=1}^{n} v_{j,f}x_j - v_{i,f}x_{i})$.\n",
"- In practice, we would throw in some L2 regularization to prevent overfitting.\n",
"\n",
"As the next section contains implementation of the algorithm from scratch, the gradient of the log loss is also provided here for completeness. The predicted value $\\hat{y}(\\textbf{x})$ is replaced with $x$ for making the notation cleaner.\n",
"\n",
"\n",
"\\begin{align}\n",
"\\frac{d}{dx}\\left[ \\ln \\big(e^{-yx} + 1 \\big) \\right] \n",
"&= \\frac{1}{e^{-yx} + 1} \\cdot \\frac{d}{dx}\\left[e^{-yx} + 1 \\right] \\\\\n",
"&= \\frac{\\frac{d}{dx}\\left[e^{-yx} \\right] + \\frac{d}{dx}\\left[1 \\right]}{e^{-yx} + 1} \\\\\n",
"&= \\frac{e^{-yx} \\cdot \\frac{d}{dx}\\left[-yx \\right] + 0}{e^{-yx} + 1} \\\\\n",
"&= \\frac{e^{-yx} \\cdot -y}{e^{-yx} + 1} \\\\\n",
"&= -\\frac{ye^{-yx}}{e^{-yx} + 1} \\\\\n",
"&= -\\frac{y}{e^{yx} + 1}\n",
"\\end{align}\n",
"\n",
"---\n",
"\n",
"**Advantages:** We'll now wrap up the theoretical section of factorization machine, with some of its advantages:\n",
"\n",
"- We can observe from the model equation that it can be computed in linear time.\n",
"- By leveraging ideas from matrix factorization, we can estimate higher order interaction effects even under very sparse data.\n",
"- Compared to traditional matrix factorization methods, which is restricted to modeling a user-item matrix, we can leverage other user or item specific features making factorization machine more flexible."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Implementation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For the implementation of factorization machine, we'll use a for loop based code as I personally find it easier to comprehend for the gradient update section. There are different ways to speed up for loop based code in Python, such as using [Cython or Numba](http://nbviewer.jupyter.org/github/ethen8181/machine-learning/blob/master/python/cython/cython.ipynb), here we'll be using Numba."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<4179x3508 sparse matrix of type ''\n",
"\twith 51261 stored elements in Compressed Sparse Row format>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# using the example spam dataset\n",
"# read it in, extract the input and output columns\n",
"label_col = 'label_num'\n",
"sms = pd.read_table('sms.tsv', header = None, names = ['label', 'message'])\n",
"sms[label_col] = sms['label'].map({'ham': 0, 'spam': 1})\n",
"X = sms['message']\n",
"y = sms[label_col].values\n",
"\n",
"# split X and y into training and testing sets\n",
"X_train, X_test, y_train, y_test = train_test_split(\n",
" X, y, test_size = 0.25, random_state = 1)\n",
"\n",
"# convert both sets' text column to document-term matrix;\n",
"# ideally, we would want to perform some preprocessing on\n",
"# our text data, but let's be lazy here as that's not\n",
"# the goal of this documentation\n",
"tfidf = TfidfVectorizer(min_df = 2, max_df = 0.5)\n",
"X_train_dtm = tfidf.fit_transform(X_train)\n",
"X_test_dtm = tfidf.transform(X_test)\n",
"X_train_dtm"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import numpy as np\n",
"from numba import njit\n",
"from tqdm import trange\n",
"from sklearn.base import BaseEstimator, ClassifierMixin\n",
"\n",
"\n",
"class FactorizationMachineClassifier(BaseEstimator, ClassifierMixin):\n",
" \"\"\"\n",
" Factorization Machine [1]_ using Stochastic Gradient Descent.\n",
" For binary classification only.\n",
"\n",
" Parameters\n",
" ----------\n",
" n_iter : int, default 10\n",
" Number of iterations to train the algorithm.\n",
"\n",
" n_factors : int, default 10\n",
" Number/dimension of features' latent factors.\n",
"\n",
" learning_rate : float, default 0.1\n",
" Learning rate for the gradient descent optimizer.\n",
"\n",
" reg_coef : float, default 0.01\n",
" Regularization strength for weights/coefficients.\n",
"\n",
" reg_factors : float, default 0.01\n",
" Regularization strength for features' latent factors.\n",
"\n",
" random_state : int, default 1234\n",
" Seed for the randomly initialized features latent factors\n",
"\n",
" verbose : bool, default True\n",
" Whether to print progress bar while training.\n",
"\n",
" Attributes\n",
" ----------\n",
" intercept_ : double\n",
" Intercept term, w0 based on the original notations.\n",
"\n",
" coef_ : 1d ndarray, shape [n_features,]\n",
" Coefficients, w based on the original notations.\n",
"\n",
" feature_factors_ : 2d ndarray, shape [n_factors, n_features]\n",
" Latent factors for all features. v based on the original\n",
" notations. The learned factors can be viewed as the\n",
" embeddings for each features. If a pair of features tends\n",
" to co-occur often, then their embeddings should be\n",
" close/similar (in terms of cosine similarity) to each other.\n",
"\n",
" history_ : list\n",
" Loss function's history at each iteration, useful\n",
" for evaluating whether the algorithm converged or not.\n",
"\n",
" References\n",
" ----------\n",
" .. [1] `S. Rendle Factorization Machines (2010)\n",
" `_ \n",
" \"\"\"\n",
"\n",
" def __init__(self, n_iter = 10, n_factors = 10,\n",
" learning_rate = 0.1, reg_coef = 0.01,\n",
" reg_factors = 0.01, random_state = 1234, verbose = False):\n",
" self.n_iter = n_iter\n",
" self.verbose = verbose\n",
" self.reg_coef = reg_coef\n",
" self.n_factors = n_factors\n",
" self.reg_factors = reg_factors\n",
" self.random_state = random_state\n",
" self.learning_rate = learning_rate\n",
"\n",
" def fit(self, X, y):\n",
" \"\"\"\n",
" Fit the model to the input data and label.\n",
"\n",
" Parameters\n",
" ----------\n",
" X : scipy sparse csr_matrix, shape [n_samples, n_features]\n",
" Data in sparse matrix format.\n",
"\n",
" y : 1d ndarray, shape [n_samples,]\n",
" Training data's corresponding label.\n",
"\n",
" Returns\n",
" -------\n",
" self\n",
" \"\"\"\n",
"\n",
" n_samples, n_features = X.shape\n",
" self.coef_ = np.zeros(n_features)\n",
" self.intercept_ = 0.0\n",
"\n",
" # the factors are often initialized with a mean of 0 and standard deviation\n",
" # of 1 / sqrt(number of latent factor specified)\n",
" np.random.seed(self.random_state)\n",
" self.feature_factors_ = np.random.normal(\n",
" scale = 1 / np.sqrt(self.n_factors), size = (self.n_factors, n_features))\n",
" \n",
" # the gradient is implemented in a way that requires\n",
" # the negative class to be labeled as -1 instead of 0\n",
" y = y.copy().astype(np.int32)\n",
" y[y == 0] = -1\n",
"\n",
" loop = range(self.n_iter)\n",
" if self.verbose:\n",
" loop = trange(self.n_iter)\n",
"\n",
" self.history_ = []\n",
" for _ in loop:\n",
" loss = _sgd_update(X.data, X.indptr, X.indices,\n",
" y, n_samples, n_features,\n",
" self.intercept_, self.coef_,\n",
" self.feature_factors_, self.n_factors,\n",
" self.learning_rate, self.reg_coef, self.reg_factors)\n",
" self.history_.append(loss)\n",
"\n",
" return self\n",
"\n",
" def predict_proba(self, X):\n",
" \"\"\"\n",
" Probability estimates. The returned estimates for\n",
" all classes are ordered by the label of classes.\n",
"\n",
" Paramters\n",
" ---------\n",
" X : scipy sparse csr_matrix, shape [n_samples, n_features]\n",
" Data in sparse matrix format.\n",
"\n",
" Returns\n",
" -------\n",
" proba : 2d ndarray, shape [n_samples, n_classes]\n",
" The probability of the sample for each class in the model.\n",
" \"\"\"\n",
" pred = self._predict(X)\n",
" pred_proba = 1.0 / (1.0 + np.exp(-pred))\n",
" proba = np.vstack((1 - pred_proba, pred_proba)).T\n",
" return proba\n",
"\n",
" def _predict(self, X):\n",
" \"\"\"Similar to _predict_instance but vectorized for all samples\"\"\"\n",
" linear_output = X * self.coef_\n",
" v = self.feature_factors_.T\n",
" term = (X * v) ** 2 - (X.power(2) * (v ** 2))\n",
" factor_output = 0.5 * np.sum(term, axis = 1)\n",
" return self.intercept_ + linear_output + factor_output\n",
"\n",
" def predict(self, X):\n",
" \"\"\"\n",
" Predict class labels for samples in X.\n",
"\n",
" Parameters\n",
" ----------\n",
" X : scipy sparse csr_matrix, shape [n_samples, n_features]\n",
" Data in sparse matrix format.\n",
"\n",
" Returns\n",
" -------\n",
" Predicted class label per sample.\n",
" \"\"\"\n",
" pred_proba = self.predict_proba(X)[:, 1]\n",
" return pred_proba.round().astype(np.int)\n",
"\n",
"\n",
"@njit\n",
"def _sgd_update(data, indptr, indices, y, n_samples, n_features,\n",
" w0, w, v, n_factors, learning_rate, reg_w, reg_v):\n",
" \"\"\"\n",
" Compute the loss of the current iteration and update\n",
" gradients accordingly.\n",
" \"\"\"\n",
" loss = 0.0\n",
" for i in range(n_samples):\n",
" pred, summed = _predict_instance(data, indptr, indices, w0, w, v, n_factors, i)\n",
" \n",
" # calculate loss and its gradient\n",
" loss += _log_loss(pred, y[i])\n",
" loss_gradient = -y[i] / (np.exp(y[i] * pred) + 1.0)\n",
" \n",
" # update bias/intercept term\n",
" w0 -= learning_rate * loss_gradient\n",
"\n",
" # update weight\n",
" for index in range(indptr[i], indptr[i + 1]):\n",
" feature = indices[index]\n",
" w[feature] -= learning_rate * (loss_gradient * data[index] + 2 * reg_w * w[feature])\n",
"\n",
" # update factor\n",
" for factor in range(n_factors):\n",
" for index in range(indptr[i], indptr[i + 1]):\n",
" feature = indices[index]\n",
" term = summed[factor] - v[factor, feature] * data[index]\n",
" v_gradient = loss_gradient * data[index] * term\n",
" v[factor, feature] -= learning_rate * (v_gradient + 2 * reg_v * v[factor, feature])\n",
" \n",
" loss /= n_samples\n",
" return loss\n",
"\n",
"\n",
"@njit\n",
"def _predict_instance(data, indptr, indices, w0, w, v, n_factors, i):\n",
" \"\"\"predicting a single instance\"\"\"\n",
" summed = np.zeros(n_factors)\n",
" summed_squared = np.zeros(n_factors)\n",
"\n",
" # linear output w * x\n",
" pred = w0\n",
" for index in range(indptr[i], indptr[i + 1]):\n",
" feature = indices[index]\n",
" pred += w[feature] * data[index]\n",
"\n",
" # factor output\n",
" for factor in range(n_factors):\n",
" for index in range(indptr[i], indptr[i + 1]):\n",
" feature = indices[index]\n",
" term = v[factor, feature] * data[index]\n",
" summed[factor] += term\n",
" summed_squared[factor] += term * term\n",
"\n",
" pred += 0.5 * (summed[factor] * summed[factor] - summed_squared[factor])\n",
" \n",
" # summed is the independent term that can be re-used\n",
" # during the gradient update stage\n",
" return pred, summed\n",
"\n",
"\n",
"@njit\n",
"def _log_loss(pred, y):\n",
" \"\"\"\n",
" negative log likelihood of the\n",
" current prediction and label, y.\n",
" \"\"\"\n",
" return np.log(np.exp(-pred * y) + 1.0)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"FactorizationMachineClassifier(learning_rate=0.1, n_factors=10, n_iter=30,\n",
" random_state=1234, reg_coef=0.01, reg_factors=0.01,\n",
" verbose=False)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fm = FactorizationMachineClassifier(n_iter = 30, learning_rate = 0.1)\n",
"fm.fit(X_train_dtm, y_train)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
""
]
},
"metadata": {
"image/png": {
"height": 392,
"width": 512
}
},
"output_type": "display_data"
}
],
"source": [
"# change default style figure and font size\n",
"plt.rcParams['figure.figsize'] = 8, 6\n",
"plt.rcParams['font.size'] = 12\n",
"\n",
"# one quick way to check that we've implemented\n",
"# the gradient descent is to ensure that the loss\n",
"# curve is steadily decreasing\n",
"plt.plot(fm.history_)\n",
"plt.title('Loss Curve Per Iteration')\n",
"plt.xlabel('Iterations')\n",
"plt.ylabel('Loss')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"auc 0.9973867907642742\n"
]
}
],
"source": [
"# predict on the test set and output the auc score\n",
"y_pred_prob = fm.predict_proba(X_test_dtm)[:, 1]\n",
"auc = roc_auc_score(y_test, y_pred_prob)\n",
"print('auc', auc)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"auc 0.9949615178092\n"
]
}
],
"source": [
"# we can compare it with a logistic regression,\n",
"logreg = LogisticRegression()\n",
"logreg.fit(X_train_dtm, y_train)\n",
"y_pred_prob = logreg.predict_proba(X_test_dtm)[:, 1]\n",
"auc = roc_auc_score(y_test, y_pred_prob)\n",
"print('auc', auc)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are various open-sourced implementations floating around the web, here are the links to some of them:\n",
"\n",
"- https://github.com/ibayer/fastFM\n",
"- https://github.com/srendle/libfm\n",
"- https://github.com/aksnzhy/xlearn\n",
"- https://github.com/scikit-learn-contrib/polylearn\n",
"\n",
"I personally haven't tested which one is more efficient, feel free to grab one of them as see if it helps solve your problem."
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"# Reference\n",
"\n",
"- [Blog: Factorization Machines](http://www.jefkine.com/recsys/2017/03/27/factorization-machines/)\n",
"- [Blog: Deep Understanding of FFM Principles and Practices (Chinese)](https://tech.meituan.com/deep-understanding-of-ffm-principles-and-practices.html)\n",
"- [Quora: What are the drawbacks of Factorization Machines?](https://www.quora.com/What-are-the-drawbacks-of-Factorization-Machines)\n",
"- [Paper: S. Rendle Factorization Machines (2010)](https://www.csie.ntu.edu.tw/~b97053/paper/Rendle2010FM.pdf)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.11"
},
"toc": {
"base_numbering": 1,
"nav_menu": {
"height": "12px",
"width": "252px"
},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": true,
"toc_position": {},
"toc_section_display": "block",
"toc_window_display": true
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}