diff --git a/_proc/02_levelSetKDEx_multivariate.ipynb b/_proc/02_levelSetKDEx_multivariate.ipynb index 8f327c4..f8fd9cc 100644 --- a/_proc/02_levelSetKDEx_multivariate.ipynb +++ b/_proc/02_levelSetKDEx_multivariate.ipynb @@ -275,7 +275,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "WARNING clustering 1446 points to 723 centroids: please provide at least 28197 training points\n" + "WARNING clustering 1446 points to 100 centroids: please provide at least 3900 training points\n" ] } ], @@ -283,10 +283,13 @@ "# RF = RandomForestRegressor(n_estimators = 10, n_jobs = 1)\n", "# RF.fit(X = XTrain, y = yTrain)\n", "\n", - "# LSKDEx = LevelSetKDEx_multivariate(estimator = RF, binSize = 2, equalBins = False)\n", + "# LSKDEx = LevelSetKDEx_multivariate_opt(estimator = RF, nClusters = 100, minClusterSize = 20)\n", "# LSKDEx.fit(X = XTrain, y = yTrain)\n", "\n", - "# weightsDataList = LSKDEx.getWeights(X = XTest, outputType='summarized')" + "# yPred = LSKDEx.estimator.predict(XTest).astype(np.float32)\n", + "# clusters = LSKDEx.kmeans.assign(yPred)[1]\n", + "\n", + "# weightsDataList = LSKDEx.getWeights(X = XTest, outputType='onlyPositiveWeights')" ] }, { @@ -295,18 +298,7 @@ "metadata": { "language": "python" }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([404, 496, 114, ..., 257, 430, 149])" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# centers = LSKDEx.centers\n", "# yPred = LSKDEx.yPredTrain\n", @@ -323,8 +315,25 @@ "metadata": { "language": "python" }, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[20 20 20 20 30 28 38 22 30 20 36 36 22 38]\n", + "20\n", + "48\n" + ] + } + ], + "source": [ + "# nPosValues = np.array([len(weightsDataList[i][0]) for i in range(len(weightsDataList))])\n", + "# print(nPosValues)\n", + "\n", + "# lenIndices = np.array([len(LSKDEx.indicesPerBin[i]) for i in range(len(LSKDEx.indicesPerBin))])\n", + "# print(min(lenIndices))\n", + "# print(max(lenIndices))" + ] } ], "metadata": { diff --git a/dddex/__pycache__/__init__.cpython-38.pyc b/dddex/__pycache__/__init__.cpython-38.pyc index 419e0a7..ff4824a 100644 Binary files a/dddex/__pycache__/__init__.cpython-38.pyc and b/dddex/__pycache__/__init__.cpython-38.pyc differ diff --git a/dddex/__pycache__/__init__.cpython-39.pyc b/dddex/__pycache__/__init__.cpython-39.pyc index 02abf8b..1110c5e 100644 Binary files a/dddex/__pycache__/__init__.cpython-39.pyc and b/dddex/__pycache__/__init__.cpython-39.pyc differ diff --git a/dddex/__pycache__/_modidx.cpython-39.pyc b/dddex/__pycache__/_modidx.cpython-39.pyc index 38194bd..1f2e5cc 100644 Binary files a/dddex/__pycache__/_modidx.cpython-39.pyc and b/dddex/__pycache__/_modidx.cpython-39.pyc differ diff --git a/dddex/__pycache__/baseClasses.cpython-38.pyc b/dddex/__pycache__/baseClasses.cpython-38.pyc index 45a1ae9..4031faf 100644 Binary files a/dddex/__pycache__/baseClasses.cpython-38.pyc and b/dddex/__pycache__/baseClasses.cpython-38.pyc differ diff --git a/dddex/__pycache__/baseClasses.cpython-39.pyc b/dddex/__pycache__/baseClasses.cpython-39.pyc index f1a5927..3525273 100644 Binary files a/dddex/__pycache__/baseClasses.cpython-39.pyc and b/dddex/__pycache__/baseClasses.cpython-39.pyc differ diff --git a/dddex/__pycache__/crossValidation.cpython-39.pyc b/dddex/__pycache__/crossValidation.cpython-39.pyc index d38bd8b..d810a02 100644 Binary files a/dddex/__pycache__/crossValidation.cpython-39.pyc and b/dddex/__pycache__/crossValidation.cpython-39.pyc differ diff --git a/dddex/__pycache__/levelSetKDEx_multivariate.cpython-39.pyc b/dddex/__pycache__/levelSetKDEx_multivariate.cpython-39.pyc index 0b03560..95bc270 100644 Binary files a/dddex/__pycache__/levelSetKDEx_multivariate.cpython-39.pyc and b/dddex/__pycache__/levelSetKDEx_multivariate.cpython-39.pyc differ diff --git a/dddex/__pycache__/levelSetKDEx_univariate.cpython-39.pyc b/dddex/__pycache__/levelSetKDEx_univariate.cpython-39.pyc index d04889b..88b7216 100644 Binary files a/dddex/__pycache__/levelSetKDEx_univariate.cpython-39.pyc and b/dddex/__pycache__/levelSetKDEx_univariate.cpython-39.pyc differ diff --git a/dddex/__pycache__/loadData.cpython-39.pyc b/dddex/__pycache__/loadData.cpython-39.pyc index ae91bbe..d871bc4 100644 Binary files a/dddex/__pycache__/loadData.cpython-39.pyc and b/dddex/__pycache__/loadData.cpython-39.pyc differ diff --git a/dddex/__pycache__/utils.cpython-38.pyc b/dddex/__pycache__/utils.cpython-38.pyc index 14de057..4926bd3 100644 Binary files a/dddex/__pycache__/utils.cpython-38.pyc and b/dddex/__pycache__/utils.cpython-38.pyc differ diff --git a/dddex/__pycache__/utils.cpython-39.pyc b/dddex/__pycache__/utils.cpython-39.pyc index da588bc..cdd232e 100644 Binary files a/dddex/__pycache__/utils.cpython-39.pyc and b/dddex/__pycache__/utils.cpython-39.pyc differ diff --git a/dddex/__pycache__/wSAA.cpython-38.pyc b/dddex/__pycache__/wSAA.cpython-38.pyc index 841803d..c7d7237 100644 Binary files a/dddex/__pycache__/wSAA.cpython-38.pyc and b/dddex/__pycache__/wSAA.cpython-38.pyc differ diff --git a/dddex/__pycache__/wSAA.cpython-39.pyc b/dddex/__pycache__/wSAA.cpython-39.pyc index 81c36b9..50e7dd6 100644 Binary files a/dddex/__pycache__/wSAA.cpython-39.pyc and b/dddex/__pycache__/wSAA.cpython-39.pyc differ diff --git a/dddex/_modidx.py b/dddex/_modidx.py index b347f28..bac4e3e 100644 --- a/dddex/_modidx.py +++ b/dddex/_modidx.py @@ -75,8 +75,6 @@ 'dddex/levelSetKDEx_multivariate.py'), 'dddex.levelSetKDEx_multivariate.LevelSetKDEx_multivariate_opt.__init__': ( 'levelsetkdex_multivariate.html#levelsetkdex_multivariate_opt.__init__', 'dddex/levelSetKDEx_multivariate.py'), - 'dddex.levelSetKDEx_multivariate.LevelSetKDEx_multivariate_opt._getEqualSizedClusters': ( 'levelsetkdex_multivariate.html#levelsetkdex_multivariate_opt._getequalsizedclusters', - 'dddex/levelSetKDEx_multivariate.py'), 'dddex.levelSetKDEx_multivariate.LevelSetKDEx_multivariate_opt.fit': ( 'levelsetkdex_multivariate.html#levelsetkdex_multivariate_opt.fit', 'dddex/levelSetKDEx_multivariate.py'), 'dddex.levelSetKDEx_multivariate.LevelSetKDEx_multivariate_opt.getWeights': ( 'levelsetkdex_multivariate.html#levelsetkdex_multivariate_opt.getweights', diff --git a/dddex/levelSetKDEx_multivariate.py b/dddex/levelSetKDEx_multivariate.py index 2ec1c1b..5f32c2f 100644 --- a/dddex/levelSetKDEx_multivariate.py +++ b/dddex/levelSetKDEx_multivariate.py @@ -372,88 +372,74 @@ def fit(self, kmeans.train(yPredMod) # Get cluster centers created by faiss. IMPORTANT NOTE: not all clusters are used! We will handle that further below. - centersAll = kmeans.centroids + centers = kmeans.centroids + clusters = np.arange(centers.shape[0]) # Compute the cluster assignment for each sample - if self.equalBins: - clusterAssignments = self._getEqualSizedClusters(y = yPredMod) - else: - clusterAssignments = kmeans.assign(yPredMod)[1] + clusterAssignments = kmeans.assign(yPredMod)[1] # Based on the clusters and cluster assignments, we can now compute the indices belonging to each bin / cluster - indicesPerBin = defaultdict(list) - binSizes = defaultdict(int) + indicesPerBin = [[] for i in range(self.nClusters)] + clusterSizes = [0 for i in range(self.nClusters)] for index, cluster in enumerate(clusterAssignments): indicesPerBin[cluster].append(index) - binSizes[cluster] += 1 + clusterSizes[cluster] += 1 - #--- + clusterSizes = np.array(clusterSizes) - clustersUsed = np.array(list(indicesPerBin.keys())) - clustersOrdered = np.sort(clustersUsed) - - centers = centersAll[clustersOrdered] - indicesPerBin = [indicesPerBin[cluster] for cluster in clustersOrdered] - binSizes = np.array([binSizes[cluster] for cluster in clustersOrdered]) + # Just needed for a check in the end + maxSizeOfExistingClusters = np.max(clusterSizes) #--- - # Merge clusters that are too small (i.e. contain less than binSize / 2 samples). # clustersTooSmall is the array of all clusters that are too small. - threshold = self.binSize / 2 - binsTooSmall = np.where(binSizes < threshold)[0] + clustersTooSmall = np.where(np.array(clusterSizes) < self.minClusterSize)[0] - if len(binsTooSmall) > 0: + if len(clustersTooSmall) > 0: + + indicesPerBinNew = copy.deepcopy(indicesPerBin) - # remove all centers from centersOld that are part of clustersTooSmall - centersNew = np.delete(centers, binsTooSmall, axis = 0) - centersTooSmall = centers[binsTooSmall] - centersNew_oldIndices = np.delete(np.arange(len(centers)), binsTooSmall) + # We are searching for the closest other cluster for each cluster that is too small + # As we don't know how many nearest neighbors we need, we are setting k to the number of clusters + nearestClusters = KDTree(centers).query(centers[clustersTooSmall], k = centers.shape[0])[1] - KDTreeNew = KDTree(centersNew) - clustersToMerge = KDTreeNew.query(centersTooSmall)[1] + # sizeNearestClusters is an array of shape (len(clustersTooSmall), self.nClusters) + sizeNearestClusters = clusterSizes[nearestClusters] - for i, clusterToMerge in enumerate(clustersToMerge): - indicesPerBin[centersNew_oldIndices[clusterToMerge]].extend(indicesPerBin[binsTooSmall[i]]) + # Calculating the cumulative sum of the cluster sizes over each row allows us to find out + # which cluster is the first one that is big enough to make the current cluster big enough + clusterSizesCumSum = np.cumsum(sizeNearestClusters, axis = 1) - # Remove the indices given by clustersTooSmall from indicesPerBin by deleting the list entry - indicesPerBin = [np.array(indices) for binIndex, indices in enumerate(indicesPerBin) if binIndex not in binsTooSmall] - binSizes = [len(indices) for indices in indicesPerBin] - binSizes = pd.Series(binSizes) + # argmax returns the first index where the condition is met. + necessaryClusters = (clusterSizesCumSum >= self.minClusterSize).argmax(axis = 1) + + # We are now creating the new indicesPerBin list by extending the indices of the clusters that are too small + for i, cluster in enumerate(clustersTooSmall): + clustersToAdd = nearestClusters[i, 0:necessaryClusters[i] + 1] + + indicesPerBinNew[cluster] = np.concatenate([indicesPerBin[cluster] for cluster in clustersToAdd]) + clusterSizes[cluster] = len(indicesPerBinNew[cluster]) - self.centers = centersNew - self.binSizes = binSizes - self.kmeans = KDTreeNew + # Following our intended logic, the resulting clusters can't be bigger than minClusterSize + maxSizeOfExistingClusters + if len(indicesPerBinNew[cluster]) > self.minClusterSize + maxSizeOfExistingClusters: + raise Warning("The cluster size is bigger than minClusterSize + maxSizeOfExistingClusters. This should not happen!") + + # indicesPerBin is only turned into a dictionary to be consistent with the other implementations of LevelSetKDEx + self.indicesPerBin = {cluster: np.array(indicesPerBinNew[cluster], dtype = 'uintc') for cluster in range(len(indicesPerBinNew))} + self.clusterSizes = pd.Series(clusterSizes) else: - self.centers = centers - self.binSizes = pd.Series(binSizes) - self.kmeans = KDTree(self.centers) - - # Transform the indices given by indicesPerBin into numpy arrays - indicesPerBin = [np.array(indices) for indices in indicesPerBin] + self.indicesPerBin = {cluster: np.array(indicesPerBin[cluster], dtype = 'uintc') for cluster in range(len(indicesPerBin))} + self.clusterSizes = pd.Series(clusterSizes) #--- self.yTrain = y self.yPredTrain = yPred - self.indicesPerBin = indicesPerBin + self.centers = centers + self.kmeans = kmeans self.fitted = True - - - #--- - - def _getEqualSizedClusters(self, - y, - ): - - centers = self.centers.reshape(-1, 1, y.shape[-1]).repeat(self.binSize, 1).reshape(-1, y.shape[-1]) - - distance_matrix = cdist(y, centers) - clusterAssignments = linear_sum_assignment(distance_matrix)[1]//self.binSize - - return clusterAssignments #--- @@ -482,16 +468,12 @@ def getWeights(self, yPred = yPred.reshape(-1, 1) #--- - - if self.equalBins: - binPerPred = self._getEqualSizedClusters(y = yPred) - - else: - binPerPred = self.kmeans.query(yPred)[1] + + clusterPerPred = self.kmeans.assign(yPred)[1] #--- - neighborsList = [self.indicesPerBin[binIndex] for binIndex in binPerPred] + neighborsList = [self.indicesPerBin[cluster] for cluster in clusterPerPred] weightsDataList = [(np.repeat(1 / len(neighbors), len(neighbors)), np.array(neighbors)) for neighbors in neighborsList] diff --git a/nbs/02_levelSetKDEx_multivariate.ipynb b/nbs/02_levelSetKDEx_multivariate.ipynb index 0104c6c..e9f04d2 100644 --- a/nbs/02_levelSetKDEx_multivariate.ipynb +++ b/nbs/02_levelSetKDEx_multivariate.ipynb @@ -460,88 +460,74 @@ " kmeans.train(yPredMod)\n", "\n", " # Get cluster centers created by faiss. IMPORTANT NOTE: not all clusters are used! We will handle that further below.\n", - " centersAll = kmeans.centroids\n", + " centers = kmeans.centroids\n", + " clusters = np.arange(centers.shape[0])\n", " \n", " # Compute the cluster assignment for each sample\n", - " if self.equalBins:\n", - " clusterAssignments = self._getEqualSizedClusters(y = yPredMod) \n", - " else:\n", - " clusterAssignments = kmeans.assign(yPredMod)[1]\n", + " clusterAssignments = kmeans.assign(yPredMod)[1]\n", " \n", " # Based on the clusters and cluster assignments, we can now compute the indices belonging to each bin / cluster\n", - " indicesPerBin = defaultdict(list)\n", - " binSizes = defaultdict(int)\n", + " indicesPerBin = [[] for i in range(self.nClusters)]\n", + " clusterSizes = [0 for i in range(self.nClusters)]\n", "\n", " for index, cluster in enumerate(clusterAssignments):\n", " indicesPerBin[cluster].append(index)\n", - " binSizes[cluster] += 1\n", + " clusterSizes[cluster] += 1\n", "\n", - " #---\n", + " clusterSizes = np.array(clusterSizes)\n", "\n", - " clustersUsed = np.array(list(indicesPerBin.keys()))\n", - " clustersOrdered = np.sort(clustersUsed)\n", - "\n", - " centers = centersAll[clustersOrdered]\n", - " indicesPerBin = [indicesPerBin[cluster] for cluster in clustersOrdered]\n", - " binSizes = np.array([binSizes[cluster] for cluster in clustersOrdered])\n", + " # Just needed for a check in the end\n", + " maxSizeOfExistingClusters = np.max(clusterSizes)\n", "\n", " #---\n", "\n", - " # Merge clusters that are too small (i.e. contain less than binSize / 2 samples).\n", " # clustersTooSmall is the array of all clusters that are too small.\n", - " threshold = self.binSize / 2\n", - " binsTooSmall = np.where(binSizes < threshold)[0]\n", + " clustersTooSmall = np.where(np.array(clusterSizes) < self.minClusterSize)[0]\n", " \n", - " if len(binsTooSmall) > 0:\n", + " if len(clustersTooSmall) > 0:\n", + " \n", + " indicesPerBinNew = copy.deepcopy(indicesPerBin)\n", "\n", - " # remove all centers from centersOld that are part of clustersTooSmall\n", - " centersNew = np.delete(centers, binsTooSmall, axis = 0)\n", - " centersTooSmall = centers[binsTooSmall]\n", - " centersNew_oldIndices = np.delete(np.arange(len(centers)), binsTooSmall)\n", + " # We are searching for the closest other cluster for each cluster that is too small\n", + " # As we don't know how many nearest neighbors we need, we are setting k to the number of clusters\n", + " nearestClusters = KDTree(centers).query(centers[clustersTooSmall], k = centers.shape[0])[1]\n", "\n", - " KDTreeNew = KDTree(centersNew)\n", - " clustersToMerge = KDTreeNew.query(centersTooSmall)[1]\n", + " # sizeNearestClusters is an array of shape (len(clustersTooSmall), self.nClusters)\n", + " sizeNearestClusters = clusterSizes[nearestClusters]\n", "\n", - " for i, clusterToMerge in enumerate(clustersToMerge):\n", - " indicesPerBin[centersNew_oldIndices[clusterToMerge]].extend(indicesPerBin[binsTooSmall[i]])\n", + " # Calculating the cumulative sum of the cluster sizes over each row allows us to find out \n", + " # which cluster is the first one that is big enough to make the current cluster big enough\n", + " clusterSizesCumSum = np.cumsum(sizeNearestClusters, axis = 1)\n", "\n", - " # Remove the indices given by clustersTooSmall from indicesPerBin by deleting the list entry\n", - " indicesPerBin = [np.array(indices) for binIndex, indices in enumerate(indicesPerBin) if binIndex not in binsTooSmall]\n", - " binSizes = [len(indices) for indices in indicesPerBin]\n", - " binSizes = pd.Series(binSizes)\n", + " # argmax returns the first index where the condition is met.\n", + " necessaryClusters = (clusterSizesCumSum >= self.minClusterSize).argmax(axis = 1)\n", + " \n", + " # We are now creating the new indicesPerBin list by extending the indices of the clusters that are too small\n", + " for i, cluster in enumerate(clustersTooSmall):\n", + " clustersToAdd = nearestClusters[i, 0:necessaryClusters[i] + 1]\n", + " \n", + " indicesPerBinNew[cluster] = np.concatenate([indicesPerBin[cluster] for cluster in clustersToAdd])\n", + " clusterSizes[cluster] = len(indicesPerBinNew[cluster])\n", "\n", - " self.centers = centersNew\n", - " self.binSizes = binSizes\n", - " self.kmeans = KDTreeNew\n", + " # Following our intended logic, the resulting clusters can't be bigger than minClusterSize + maxSizeOfExistingClusters\n", + " if len(indicesPerBinNew[cluster]) > self.minClusterSize + maxSizeOfExistingClusters:\n", + " raise Warning(\"The cluster size is bigger than minClusterSize + maxSizeOfExistingClusters. This should not happen!\")\n", + "\n", + " # indicesPerBin is only turned into a dictionary to be consistent with the other implementations of LevelSetKDEx\n", + " self.indicesPerBin = {cluster: np.array(indicesPerBinNew[cluster], dtype = 'uintc') for cluster in range(len(indicesPerBinNew))}\n", + " self.clusterSizes = pd.Series(clusterSizes)\n", " \n", " else:\n", - " self.centers = centers\n", - " self.binSizes = pd.Series(binSizes)\n", - " self.kmeans = KDTree(self.centers)\n", - "\n", - " # Transform the indices given by indicesPerBin into numpy arrays\n", - " indicesPerBin = [np.array(indices) for indices in indicesPerBin]\n", + " self.indicesPerBin = {cluster: np.array(indicesPerBin[cluster], dtype = 'uintc') for cluster in range(len(indicesPerBin))}\n", + " self.clusterSizes = pd.Series(clusterSizes)\n", " \n", " #---\n", " \n", " self.yTrain = y\n", " self.yPredTrain = yPred\n", - " self.indicesPerBin = indicesPerBin\n", + " self.centers = centers\n", + " self.kmeans = kmeans\n", " self.fitted = True\n", - " \n", - " \n", - " #---\n", - " \n", - " def _getEqualSizedClusters(self,\n", - " y,\n", - " ):\n", - " \n", - " centers = self.centers.reshape(-1, 1, y.shape[-1]).repeat(self.binSize, 1).reshape(-1, y.shape[-1])\n", - "\n", - " distance_matrix = cdist(y, centers)\n", - " clusterAssignments = linear_sum_assignment(distance_matrix)[1]//self.binSize\n", - "\n", - " return clusterAssignments\n", "\n", " #---\n", " \n", @@ -570,16 +556,12 @@ " yPred = yPred.reshape(-1, 1)\n", " \n", " #---\n", - " \n", - " if self.equalBins:\n", - " binPerPred = self._getEqualSizedClusters(y = yPred)\n", - " \n", - " else:\n", - " binPerPred = self.kmeans.query(yPred)[1]\n", + "\n", + " clusterPerPred = self.kmeans.assign(yPred)[1]\n", " \n", " #---\n", " \n", - " neighborsList = [self.indicesPerBin[binIndex] for binIndex in binPerPred]\n", + " neighborsList = [self.indicesPerBin[cluster] for cluster in clusterPerPred]\n", " \n", " weightsDataList = [(np.repeat(1 / len(neighbors), len(neighbors)), np.array(neighbors)) for neighbors in neighborsList]\n", " \n", @@ -657,7 +639,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "WARNING clustering 1446 points to 723 centroids: please provide at least 28197 training points\n" + "WARNING clustering 1446 points to 100 centroids: please provide at least 3900 training points\n" ] } ], @@ -665,28 +647,20 @@ "# RF = RandomForestRegressor(n_estimators = 10, n_jobs = 1)\n", "# RF.fit(X = XTrain, y = yTrain)\n", "\n", - "# LSKDEx = LevelSetKDEx_multivariate(estimator = RF, binSize = 2, equalBins = False)\n", + "# LSKDEx = LevelSetKDEx_multivariate_opt(estimator = RF, nClusters = 100, minClusterSize = 20)\n", "# LSKDEx.fit(X = XTrain, y = yTrain)\n", "\n", - "# weightsDataList = LSKDEx.getWeights(X = XTest, outputType='summarized')" + "# yPred = LSKDEx.estimator.predict(XTest).astype(np.float32)\n", + "# clusters = LSKDEx.kmeans.assign(yPred)[1]\n", + "\n", + "# weightsDataList = LSKDEx.getWeights(X = XTest, outputType='onlyPositiveWeights')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([404, 496, 114, ..., 257, 430, 149])" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# centers = LSKDEx.centers\n", "# yPred = LSKDEx.yPredTrain\n", @@ -701,8 +675,25 @@ "execution_count": null, "id": "10e14eb7", "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[20 20 20 20 30 28 38 22 30 20 36 36 22 38]\n", + "20\n", + "48\n" + ] + } + ], + "source": [ + "# nPosValues = np.array([len(weightsDataList[i][0]) for i in range(len(weightsDataList))])\n", + "# print(nPosValues)\n", + "\n", + "# lenIndices = np.array([len(LSKDEx.indicesPerBin[i]) for i in range(len(LSKDEx.indicesPerBin))])\n", + "# print(min(lenIndices))\n", + "# print(max(lenIndices))" + ] } ], "metadata": {