forked from Open-Deep-ML/DML-OpenProblem
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path17.json
More file actions
69 lines (69 loc) · 9.9 KB
/
Copy path17.json
File metadata and controls
69 lines (69 loc) · 9.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
{
"id": "17",
"title": "K-Means Clustering",
"difficulty": "medium",
"category": "Machine Learning",
"video": "https://youtu.be/KzJORp8bgqs?si=BBrGGuCAWt_AA8QV",
"likes": "0",
"dislikes": "0",
"contributor": [
{
"profile_link": "https://github.com/Haleshot",
"name": "Srihari Thyagarajan"
}
],
"tinygrad_difficulty": "medium",
"pytorch_difficulty": "medium",
"marimo_link": "https://adityakhalkar.github.io/Deep-ML-x-Marimo/17",
"description": "Your task is to write a Python function that implements the k-Means clustering algorithm. This function should take specific inputs and produce a list of final centroids. k-Means clustering is a method used to partition `n` points into `k` clusters. The goal is to group similar points together and represent each group by its center (called the *centroid*).\n\n### Function Inputs:\n\n- `points`: A list of points, where each point is a tuple of coordinates (e.g., `(x, y)` for 2D points)\n- `k`: An integer representing the number of clusters to form\n- `initial_centroids`: A list of initial centroid points, each a tuple of coordinates\n- `max_iterations`: An integer representing the maximum number of iterations to perform\n\n### Function Output:\n\nA list of the final centroids of the clusters, where each centroid is rounded to the nearest fourth decimal.",
"learn_section": "\n## K-Means Clustering Algorithm Implementation\n\n### Algorithm Steps\n\n1. **Initialization** \n Use the provided `initial_centroids` as your starting point. This step is already done for you in the input.\n\n2. **Assignment Step** \n For each point in your dataset:\n - Calculate its distance to each centroid.\n - Assign the point to the cluster of the nearest centroid. \n *Hint*: Consider creating a helper function to calculate the Euclidean distance between two points.\n\n3. **Update Step** \n For each cluster:\n - Calculate the mean of all points assigned to the cluster.\n - Update the centroid to this new mean position. \n *Hint*: Be careful with potential empty clusters. Decide how you'll handle them (e.g., keep the previous centroid).\n\n4. **Iteration** \n Repeat steps 2 and 3 until either:\n - The centroids no longer change significantly (this case does not need to be included in your solution), or\n - You reach the `max_iterations` limit. \n *Hint*: You might want to keep track of the previous centroids to check for significant changes.\n\n5. **Result** \n Return the list of final centroids, ensuring each coordinate is rounded to the nearest fourth decimal.",
"starter_code": "def k_means_clustering(points: list[tuple[float, float]], k: int, initial_centroids: list[tuple[float, float]], max_iterations: int) -> list[tuple[float, float]]:\n\t# Your code here\n\treturn final_centroids",
"solution": "\nimport numpy as np\n\ndef euclidean_distance(a, b):\n return np.sqrt(((a - b) ** 2).sum(axis=1))\n\ndef k_means_clustering(points, k, initial_centroids, max_iterations):\n points = np.array(points)\n centroids = np.array(initial_centroids)\n \n for iteration in range(max_iterations):\n # Assign points to the nearest centroid\n distances = np.array([euclidean_distance(points, centroid) for centroid in centroids])\n assignments = np.argmin(distances, axis=0)\n\n new_centroids = np.array([points[assignments == i].mean(axis=0) if len(points[assignments == i]) > 0 else centroids[i] for i in range(k)])\n \n # Check for convergence\n if np.all(centroids == new_centroids):\n break\n centroids = new_centroids\n centroids = np.round(centroids,4)\n return [tuple(centroid) for centroid in centroids]",
"example": {
"input": "points = [(1, 2), (1, 4), (1, 0), (10, 2), (10, 4), (10, 0)], k = 2, initial_centroids = [(1, 1), (10, 1)], max_iterations = 10",
"output": "[(1, 2), (10, 2)]",
"reasoning": "Given the initial centroids and a maximum of 10 iterations,\n the points are clustered around these points, and the centroids are\n updated to the mean of the assigned points, resulting in the final\n centroids which approximate the means of the two clusters.\n The exact number of iterations needed may vary,\n but the process will stop after 10 iterations at most."
},
"test_cases": [
{
"test": "print(k_means_clustering([(1, 2), (1, 4), (1, 0), (10, 2), (10, 4), (10, 0)], 2, [(1, 1), (10, 1)], 10))",
"expected_output": "[(1.0, 2.0), (10.0, 2.0)]"
},
{
"test": "print(k_means_clustering([(0, 0, 0), (2, 2, 2), (1, 1, 1), (9, 10, 9), (10, 11, 10), (12, 11, 12)], 2, [(1, 1, 1), (10, 10, 10)], 10))",
"expected_output": "[(1.0, 1.0, 1.0), (10.3333, 10.6667, 10.3333)]"
},
{
"test": "print(k_means_clustering([(1, 1), (2, 2), (3, 3), (4, 4)], 1, [(0,0)], 10))",
"expected_output": "[(2.5, 2.5)]"
},
{
"test": "print(k_means_clustering([(0, 0), (1, 0), (0, 1), (1, 1), (5, 5), (6, 5), (5, 6), (6, 6),(0, 5), (1, 5), (0, 6), (1, 6), (5, 0), (6, 0), (5, 1), (6, 1)], 4, [(0, 0), (0, 5), (5, 0), (5, 5)], 10))",
"expected_output": "[(0.5, 0.5), (0.5, 5.5), (5.5, 0.5), (5.5, 5.5)]"
}
],
"tinygrad_starter_code": "from tinygrad.tensor import Tensor\n\ndef k_means_clustering_tg(points, k, initial_centroids, max_iterations) -> list[tuple[float, ...]]:\n \"\"\"\n Perform k-means clustering on `points` into `k` clusters using tinygrad.\n points: list of lists or Tensor, shape (n_points, n_features)\n initial_centroids: list of lists or Tensor, shape (k, n_features)\n max_iterations: maximum number of iterations\n Returns a list of k centroids as tuples, rounded to 4 decimals.\n \"\"\"\n # Your implementation here\n pass",
"tinygrad_solution": "import numpy as np\nfrom tinygrad.tensor import Tensor\n\ndef k_means_clustering_tg(points, k, initial_centroids, max_iterations) -> list[tuple[float, ...]]:\n \"\"\"\n Perform k-means clustering on `points` into `k` clusters using tinygrad.\n points: list of lists or Tensor, shape (n_points, n_features)\n initial_centroids: list of lists or Tensor, shape (k, n_features)\n max_iterations: maximum number of iterations\n Returns a list of k centroids as tuples, rounded to 4 decimals.\n \"\"\"\n pts = np.array(points, dtype=float)\n centroids = np.array(initial_centroids, dtype=float)\n for _ in range(max_iterations):\n # compute distances (k, n_points)\n dists = np.array([np.linalg.norm(pts - c, axis=1) for c in centroids])\n # assign points\n assignments = dists.argmin(axis=0)\n new_centroids = np.array([\n pts[assignments == i].mean(axis=0) if np.any(assignments == i) else centroids[i]\n for i in range(k)\n ])\n new_centroids = np.round(new_centroids, 4)\n if np.array_equal(new_centroids, centroids):\n break\n centroids = new_centroids\n return [tuple(c.tolist()) for c in centroids]",
"tinygrad_test_cases": [
{
"test": "res = k_means_clustering_tg(\n [[0.0,0.0],[0.1,0.1],[10.0,10.0],[10.1,10.1]],\n 2,\n [[0.0,0.0],[10.0,10.0]],\n 10\n)\nprint(res)",
"expected_output": "[(0.05, 0.05), (10.05, 10.05)]"
},
{
"test": "res = k_means_clustering_tg(\n [[1.0,2.0],[3.0,4.0]],\n 1,\n [[1.0,2.0]],\n 10\n)\nprint(res)",
"expected_output": "[(2.0, 3.0)]"
}
],
"pytorch_starter_code": "import torch\n\ndef k_means_clustering(points, k, initial_centroids, max_iterations) -> list[tuple[float, ...]]:\n \"\"\"\n Perform k-means clustering on `points` into `k` clusters.\n points: tensor of shape (n_points, n_features)\n initial_centroids: tensor of shape (k, n_features)\n max_iterations: maximum number of iterations\n Returns a list of k centroids as tuples, rounded to 4 decimals.\n \"\"\"\n # Convert to tensors\n points_t = torch.as_tensor(points, dtype=torch.float)\n centroids = torch.as_tensor(initial_centroids, dtype=torch.float)\n # Your implementation here\n pass",
"pytorch_solution": "import torch\n\ndef k_means_clustering(points, k, initial_centroids, max_iterations) -> list[tuple[float, ...]]:\n \"\"\"\n Perform k-means clustering on `points` into `k` clusters.\n points: tensor of shape (n_points, n_features)\n initial_centroids: tensor of shape (k, n_features)\n max_iterations: maximum number of iterations\n Returns a list of k centroids as tuples, rounded to 4 decimals.\n \"\"\"\n points_t = torch.as_tensor(points, dtype=torch.float)\n centroids = torch.as_tensor(initial_centroids, dtype=torch.float)\n for _ in range(max_iterations):\n # compute distances (k, n_points)\n diffs = points_t.unsqueeze(0) - centroids.unsqueeze(1)\n distances = torch.sqrt((diffs ** 2).sum(dim=2))\n # assign each point to nearest centroid\n assignments = distances.argmin(dim=0)\n new_centroids = []\n for i in range(k):\n cluster_points = points_t[assignments == i]\n if cluster_points.numel() == 0:\n new_centroids.append(centroids[i])\n else:\n new_centroids.append(cluster_points.mean(dim=0))\n new_centroids = torch.stack(new_centroids)\n new_centroids = torch.round(new_centroids * 10000) / 10000\n if torch.equal(new_centroids, centroids):\n break\n centroids = new_centroids\n return [tuple(c.tolist()) for c in centroids]",
"pytorch_test_cases": [
{
"test": "import torch\nres = k_means_clustering(\n torch.tensor([[0.0,0.0],[0.1,0.1],[10.0,10.0],[10.1,10.1]]),\n 2,\n torch.tensor([[0.0,0.0],[10.0,10.0]]),\n 10\n)\nprint(res)",
"expected_output": "[(0.05, 0.05), (10.05, 10.05)]"
},
{
"test": "import torch\nres = k_means_clustering(\n torch.tensor([[1.0,2.0],[3.0,4.0]]),\n 1,\n torch.tensor([[1.0,2.0]]),\n 10\n)\nprint(res)",
"expected_output": "[(2.0, 3.0)]"
}
]
}