Created
May 18, 2025 14:53
-
-
Save tang-hi/3ef51ddab75961a3a80304aeec348bd9 to your computer and use it in GitHub Desktop.
angle-dimension
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
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| def angle_between_vectors(v1, v2): | |
| """Calculates the angle in degrees between two vectors.""" | |
| v1_u = v1 / np.linalg.norm(v1) | |
| v2_u = v2 / np.linalg.norm(v2) | |
| dot_product = np.dot(v1_u, v2_u) | |
| # Clip dot_product to avoid acos domain errors due to floating point inaccuracies | |
| clipped_dot_product = np.clip(dot_product, -1.0, 1.0) | |
| angle_radians = np.arccos(clipped_dot_product) | |
| angle_degrees = np.degrees(angle_radians) | |
| return angle_degrees | |
| # Parameters for the experiment | |
| dimensions = [2, 10, 100, 1000] | |
| num_vector_pairs = 10000 # Number of random vector pairs to generate for each dimension | |
| num_bins = 60 # Number of bins for the histogram | |
| plt.figure(figsize=(12, 7)) | |
| for dim in dimensions: | |
| angles = [] | |
| for _ in range(num_vector_pairs): | |
| # Generate two random vectors. | |
| # Components are drawn from a standard normal distribution (mean 0, variance 1). | |
| # This ensures that vector directions are uniformly distributed on the hypersphere. | |
| vec1 = np.random.randn(dim) | |
| vec2 = np.random.randn(dim) | |
| # Calculate the angle between the two vectors | |
| if np.linalg.norm(vec1) > 0 and np.linalg.norm(vec2) > 0: # Avoid zero vectors | |
| angle = angle_between_vectors(vec1, vec2) | |
| angles.append(angle) | |
| else: | |
| # This case should be rare with randn but good to be safe | |
| continue | |
| # Plot the histogram of angles for the current dimension | |
| # density=True normalizes the histogram to form a probability density | |
| plt.hist(angles, bins=num_bins, density=True, histtype='step', linewidth=1.5, label=f'Dimension = {dim}') | |
| plt.title('Angle Distribution Between Random Vectors') | |
| plt.xlabel('Angle (Degrees)') | |
| plt.ylabel('Frequency Density') | |
| plt.legend(title='Vector Dimensionality') | |
| plt.grid(True, linestyle='--', alpha=0.6) | |
| plt.xlim(0, 180) # Angles range from 0 to 180 degrees | |
| # Highlight the 90-degree mark | |
| plt.axvline(90, color='black', linestyle='dashed', linewidth=1, label='90 Degrees (Orthogonal)') | |
| # Ensure 90 is a tick on the x-axis for clarity | |
| current_ticks = list(plt.xticks()[0]) | |
| if 90 not in current_ticks: | |
| current_ticks.append(90) | |
| current_ticks.sort() | |
| plt.xticks(current_ticks) | |
| # Adjust legend to include the axvline if needed, or ensure it's clear | |
| handles, labels = plt.gca().get_legend_handles_labels() | |
| # The axvline doesn't automatically add to legend this way, so we'll rely on its visual distinctness | |
| # Or, we can add it manually if really needed, but it might clutter. | |
| # For now, the existing legend for dimensions is primary. | |
| plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment