vectorized update_a

This commit is contained in:
Ritchie 2018-05-18 13:49:47 +02:00
parent 49e7cc6a7e
commit 7e29d4aee8

View File

@ -38,9 +38,12 @@
"source": [
"n = 50\n",
"size = (n, 2)\n",
"\n",
"np.random.seed(1)\n",
"x = np.random.normal(0, 1, size)\n",
"x = np.append(x, np.random.normal(5, 1, size), axis=0)\n",
"\n",
"# x = StandardScaler().fit_transform(x)\n",
"\n",
"c = ['r' for _ in range(n)] + ['b' for _ in range(n)]\n",
"plt.scatter(x[:, 0], x[:, 1], c=c)\n",
"plt.show()"
@ -71,18 +74,7 @@
" for j in range(x.shape[0]):\n",
" S[i, j] = similarity(x[i], x[j])\n",
" \n",
" return A, R, S\n",
"\n",
"A, R, S = create_matrices()\n",
"S"
]
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"A, R, S = create_matrices()"
" return A, R, S\n"
]
},
{
@ -97,36 +89,40 @@
"metadata": {},
"outputs": [],
"source": [
"def update_r(lmda=0.9):\n",
" # For every column k, except for the column with the maximum value the max is the same.\n",
" # So we can subtract the maximum for every row, and only need to do something different for k == argmax\n",
" \n",
"def update_r(lmda=0.9, slow=False):\n",
" global R\n",
" v = S + A\n",
" rows = np.arange(x.shape[0])\n",
" # We only compare the current point to all other points, so the diagonal can be filled with -infinity\n",
" np.fill_diagonal(v, -np.inf)\n",
" if slow:\n",
" for i in range(x.shape[0]):\n",
" for k in range(x.shape[0]):\n",
" v = S[i, :] + A[i, :]\n",
" v[k] = -np.inf\n",
" v[i]= -np.inf\n",
" R[i, k] = R[i, k] * lmda + (1 - lmda) * (S[i, k] - np.max(v))\n",
" \n",
" # max values\n",
" idx_max = np.argmax(v, axis=1)\n",
" first_max = v[rows, idx_max]\n",
" \n",
" # Second max values. For every column where k is the max value.\n",
" v[rows, idx_max] = -np.inf\n",
" second_max = v[rows, np.argmax(v, axis=1)]\n",
" \n",
" # Broadcast the maximum value per row over all the columns per row.\n",
" max_matrix = np.zeros_like(R) + first_max[:, None]\n",
" max_matrix[rows, idx_max] = second_max\n",
" \n",
" max_matrix = S - max_matrix\n",
" \n",
" R = R * lmda + (1 - lmda) * R_new\n",
" else:\n",
" # For every column k, except for the column with the maximum value the max is the same.\n",
" # So we can subtract the maximum for every row, and only need to do something different for k == argmax\n",
" \n",
" v = S + A\n",
" rows = np.arange(x.shape[0])\n",
" # We only compare the current point to all other points, so the diagonal can be filled with -infinity\n",
" np.fill_diagonal(v, -np.inf)\n",
"\n",
" \n",
"A, R, S = create_matrices()\n",
"update_r()\n",
"R"
" # max values\n",
" idx_max = np.argmax(v, axis=1)\n",
" first_max = v[rows, idx_max]\n",
"\n",
" # Second max values. For every column where k is the max value.\n",
" v[rows, idx_max] = -np.inf\n",
" second_max = v[rows, np.argmax(v, axis=1)]\n",
"\n",
" # Broadcast the maximum value per row over all the columns per row.\n",
" max_matrix = np.zeros_like(R) + first_max[:, None]\n",
" max_matrix[rows, idx_max] = second_max\n",
"\n",
" new_val = S - max_matrix\n",
"\n",
" R = R * lmda + (1 - lmda) * new_val"
]
},
{
@ -137,27 +133,10 @@
]
},
{
"cell_type": "code",
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"np.diag(k)"
]
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"A, R, S = create_matrices()\n",
"preference = np.median(S)\n",
"# update_r()\n",
"\n",
"i, k = np.meshgrid(np.arange(100), np.arange(100))\n",
"\n",
"v = S + A\n",
"\n",
"v[i, k] = -np.inf\n"
"$ a(k, k) \\leftarrow \\sum\\limits_{i' \\neq k}\\max(0, r(i', k)) $"
]
},
{
@ -167,20 +146,48 @@
},
"outputs": [],
"source": [
"def update_a(lmda=0.9):\n",
" for i in range(x.shape[0]):\n",
" for k in range(x.shape[0]):\n",
" v = np.array(R[:, k])\n",
" if i != k:\n",
" v[i] = -np.inf\n",
" v[k] = - np.inf\n",
" v[v < 0] = 0\n",
"def update_a(lmda=0.9, slow=False):\n",
" global A\n",
" \n",
" if slow:\n",
" for i in range(x.shape[0]):\n",
" for k in range(x.shape[0]):\n",
" v = np.array(R[:, k])\n",
" if i != k:\n",
" v[i] = -np.inf\n",
" v[k] = - np.inf\n",
" v[v < 0] = 0\n",
"\n",
" A[i, k] = A[i, k] * lmda + (1 - lmda) * min(0, R[k, k] + v.sum())\n",
" else:\n",
" v[k] = -np.inf\n",
" v[v < 0] = 0\n",
" A[k, k] = A[k, k] * lmda + (1 - lmda) * v.sum()\n",
" A[i, k] = A[i, k] * lmda + (1 - lmda) * min(0, R[k, k] + v.sum())\n",
" else:\n",
" v[k] = -np.inf\n",
" v[v < 0] = 0\n",
" A[k, k] = A[k, k] * lmda + (1 - lmda) * v.sum()\n",
" else:\n",
" k_k_idx = np.arange(x.shape[0])\n",
" # set a(i, k)\n",
" v = np.array(R)\n",
" v[v < 0] = 0\n",
" np.fill_diagonal(v, 0)\n",
" v = v.sum(axis=0) # columnwise sum\n",
" v = v + R[k_k_idx, k_k_idx]\n",
"\n",
" # broadcasting of columns 'r(k, k) + sum(max(0, r(i', k))) to rows.\n",
" v = np.ones(A.shape) * v\n",
"\n",
" # For every column k, subtract the positive value of k. \n",
" # This value is included in the sum and shouldn't be\n",
" v -= np.clip(R, 0, np.inf)\n",
" v[v > 0] = 0\n",
" \n",
" # set(a(k, k))\n",
" v_ = np.array(R)\n",
" np.fill_diagonal(v_, 0)\n",
"\n",
" v_[v_ < 0] = 0\n",
"\n",
" v[k_k_idx, k_k_idx] = v_.sum(axis=0) # column wise sum\n",
" A = A * lmda + (1 - lmda) * v\n",
"\n",
"def plot_iteration(A, R):\n",
" fig = plt.figure(figsize=(12, 6))\n",
@ -228,9 +235,9 @@
"damping = 0.5\n",
"\n",
"figures = []\n",
"for i in range(20):\n",
"for i in range(50):\n",
" update_r(damping)\n",
" update_a(damping)\n",
" update_a(damping, 0)\n",
" \n",
" if i % 5 == 0:\n",
" fig, labels, exemplars = plot_iteration(A, R)\n",