Optimize Fuzzy C Means - #432
Open
andrewdalpino wants to merge 1 commit into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Optimizes Fuzzy C-Means training by caching distances and streamlining centroid updates.
Changes:
- Reuses per-epoch distance and membership matrices.
- Aggregates weighted centroid sums in one pass.
- Extracts shared membership calculation logic.
A moderate issue remains: preserve raw distances for inertia and apply EPSILON only when deriving memberships to retain exact-match loss semantics.
Suppressed comments (4)
src/Clusterers/FuzzyCMeans.php:293
- This path no longer calls
probaSample(), although that protected method is the hook used bypredictSample()and is not marked@internal. A subclass overriding it to customize memberships will therefore train with the base implementation but predict with the override, making the estimator's training and prediction behavior inconsistent. Preserve the existing hook in the cached-distance design or explicitly make this a documented breaking change.
$memberships[] = $this->membershipsFromDistances($row);
src/Clusterers/FuzzyCMeans.php:277
numFeatures()reads$samples[0], butUnlabeled::quick()/theverify=falseconstructor preserves arbitrary row keys. A dataset such as[10 => [1.0], 11 => [2.0]]therefore reports zero features here, leaving every$sums[$cluster]empty and preventing centroid updates. Normalize the samples once (and use that normalized array throughout the epoch) or derive the dimensionality from the first iterated sample.
$numFeatures = $dataset->numFeatures();
src/Clusterers/FuzzyCMeans.php:322
- The first pass appends memberships with
[], creating a packed list, while this pass indexes it with the dataset's original row key.Unlabeled::quick()can preserve non-sequential keys, so[0 => [...], 2 => [...]]reaches an undefined$memberships[2]offset (and can associate rows incorrectly). Iterate over normalized samples or preserve the original keys when building$memberships.
foreach ($dataset->samples() as $i => $sample) {
foreach ($memberships[$i] as $cluster => $membership) {
src/Clusterers/FuzzyCMeans.php:328
- This update also assumes feature vectors have zero-based contiguous keys:
$sumsis initialized with keys0..$numFeatures-1, but$jcomes directly from each sample. SinceUnlabeled::quick()can preserve feature keys, a sample like[10 => 1.0, 20 => 2.0]now indexes nonexistent sum entries and fails to update the centroid; the previous transpose path reindexed columns. Iterate overarray_values($sample)(or normalize the dataset) before accumulating.
foreach ($sample as $j => $value) {
$sums[$cluster][$j] += $weight * $value;
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| $row = []; | ||
|
|
||
| foreach ($this->centroids as $centroid) { | ||
| $row[] = $this->kernel->compute($sample, $centroid) ?: EPSILON; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FuzzyCMeans computes every sample↔centroid distance twice per epoch — inertia() at src/Clusterers/FuzzyCMeans.php:436 recomputes what probaSample already did, and the membership-exponent + total sum is computed a redundant factor-of-f (times feature count) in the centroid update. Compute the n×c distance matrix + weighted matrix once per epoch. ~2× epoch cost.