carterwward commited on
Commit
38096b2
1 Parent(s): c9da403

add direction tracking functionality to evolutionary algorithm, updat git ignore

Browse files
.gitignore CHANGED
@@ -7,3 +7,5 @@
7
  /data/songs_new.csv
8
  __pycache__
9
  *.code-workspace
 
 
 
7
  /data/songs_new.csv
8
  __pycache__
9
  *.code-workspace
10
+ imgs/
11
+ .DS_Store
my_cache_handler.py DELETED
@@ -1,3 +0,0 @@
1
- from spotipy.cache_handler import CacheHandler
2
-
3
- class CacheFileHandler(CacheHandler):
 
 
 
 
src/evolutionary_alrogithm.py CHANGED
@@ -1,14 +1,18 @@
1
  import pandas as pd
2
  import numpy as np
 
 
3
  import gradio as gr
4
  import plotly.express as px
5
  from plotly.graph_objects import Figure
 
6
  from copy import deepcopy
7
  from random import choice
8
  from typing import List, Set
9
  import itertools
10
  from sklearn.preprocessing import StandardScaler
11
  from src.spotipy_utils import SpotifyTrack, get_sp_client
 
12
 
13
  # Initial data cleaning.
14
  SONG_DF = pd.read_csv("data/SpotifyAudioFeaturesApril2019.csv")
@@ -127,7 +131,7 @@ class Population:
127
  self.crossover_function = crossover_function
128
  self.mutation_size = mutation_size
129
  self.history_df = deepcopy(history_df)
130
-
131
 
132
  def mutate(self, thumbs_up:List[Individual], thumbs_down:List[Individual], added_songs:List[Individual]):
133
  """ Method to call assigned mutation function through.
@@ -201,6 +205,35 @@ class Population:
201
  },)
202
 
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  def update_population_history(self, thumbs_up:List[Individual], thumbs_down:List[Individual], added_songs:List[Individual]):
205
  """ Update the DF keeping track of the traversal history.
206
 
@@ -283,11 +316,17 @@ def simple_mutation(population: Population, thumbs_up:List[Individual], thumbs_d
283
  """
284
  liked_tracks = list(itertools.chain(*[thumbs_up, added_songs]))
285
  new_track_inds = set()
 
 
286
  for i in range(population.size):
287
  liked_track = choice(liked_tracks)
288
  mutated_track_genome = liked_track.genome + np.random.uniform(size=(population.size))*population.mutation_size
289
  child = get_closest_song_to_genome(population, mutated_track_genome, new_track_inds)
 
 
290
  population.pop[i] = child
 
 
291
 
292
 
293
  def differential_mutation(population: Population, thumbs_up:List[Individual], thumbs_down:List[Individual], added_songs:List[Individual]):
@@ -300,6 +339,8 @@ def differential_mutation(population: Population, thumbs_up:List[Individual], th
300
  added_songs (List[Individual]): List of individuals added to the playlist.
301
  """
302
  new_track_inds = set()
 
 
303
  for i in range(population.size):
304
  if thumbs_down:
305
  disliked_track = choice(thumbs_down)
@@ -321,4 +362,8 @@ def differential_mutation(population: Population, thumbs_up:List[Individual], th
321
  gene_distances = attracting_track.genome - disliked_track.genome
322
  resulting_genome = seed_track.genome + gene_distances*population.mutation_size
323
  child = get_closest_song_to_genome(population, resulting_genome, new_track_inds)
 
 
324
  population.pop[i] = child
 
 
 
1
  import pandas as pd
2
  import numpy as np
3
+ from scipy.spatial.distance import cosine
4
+ import scikits.bootstrap as bootstrap
5
  import gradio as gr
6
  import plotly.express as px
7
  from plotly.graph_objects import Figure
8
+ import matplotlib.pyplot as plt
9
  from copy import deepcopy
10
  from random import choice
11
  from typing import List, Set
12
  import itertools
13
  from sklearn.preprocessing import StandardScaler
14
  from src.spotipy_utils import SpotifyTrack, get_sp_client
15
+ # plt.switch_backend('Agg') # NOTE: for traversal direction tracking viz
16
 
17
  # Initial data cleaning.
18
  SONG_DF = pd.read_csv("data/SpotifyAudioFeaturesApril2019.csv")
 
131
  self.crossover_function = crossover_function
132
  self.mutation_size = mutation_size
133
  self.history_df = deepcopy(history_df)
134
+ self.distance_matrices = []
135
 
136
  def mutate(self, thumbs_up:List[Individual], thumbs_down:List[Individual], added_songs:List[Individual]):
137
  """ Method to call assigned mutation function through.
 
205
  },)
206
 
207
 
208
+ def generate_direction_tracking(self):
209
+ multidim_distance = np.stack(self.distance_matrices, axis=2)
210
+
211
+ # Compute distribution of cosine similarity amongst distance vectors between individuals of the same generation.
212
+ sibling_directional_similarity = np.zeros((multidim_distance.shape[2], multidim_distance.shape[0]*(multidim_distance.shape[0]-1)))
213
+ for t in range(multidim_distance.shape[2]):
214
+ cosine_similarities = []
215
+ for i in range(multidim_distance.shape[0]):
216
+ for j in range(multidim_distance.shape[0]):
217
+ if i == j:
218
+ continue
219
+
220
+ cosine_similarity = cosine(multidim_distance[i,:,t], multidim_distance[j,:,t])
221
+
222
+ cosine_similarities.append(cosine_similarity)
223
+
224
+ sibling_directional_similarity[t, :] = np.array(cosine_similarities)
225
+ num_obs = sibling_directional_similarity.shape[0]
226
+ # Compute bootstrapped CI
227
+ data_ci = [bootstrap.ci(sibling_directional_similarity[k, :]) for k in range(num_obs)]
228
+ means = [ci.sum() / 2 for ci in data_ci]
229
+ lower = [ci[0] for ci in data_ci]
230
+ upper = [ci[1] for ci in data_ci]
231
+
232
+ plt.plot(means, label = "Distribution of Cosine Similarity for Paternal Distance Vectors Among Siblings Over Time")
233
+ plt.fill_between(np.arange(num_obs), upper, lower, alpha = 0.5)
234
+ plt.savefig("cosine_dist_over_time.png")
235
+
236
+
237
  def update_population_history(self, thumbs_up:List[Individual], thumbs_down:List[Individual], added_songs:List[Individual]):
238
  """ Update the DF keeping track of the traversal history.
239
 
 
316
  """
317
  liked_tracks = list(itertools.chain(*[thumbs_up, added_songs]))
318
  new_track_inds = set()
319
+ # Init population distance matrix
320
+ distance_matrix = np.zeros((population.size, population.size))
321
  for i in range(population.size):
322
  liked_track = choice(liked_tracks)
323
  mutated_track_genome = liked_track.genome + np.random.uniform(size=(population.size))*population.mutation_size
324
  child = get_closest_song_to_genome(population, mutated_track_genome, new_track_inds)
325
+ # Record distance vector for parent-child.
326
+ distance_matrix[i, :] = child.genome - liked_track.genome
327
  population.pop[i] = child
328
+ # Add to distance matrix tracking list.
329
+ population.distance_matrices.append(distance_matrix)
330
 
331
 
332
  def differential_mutation(population: Population, thumbs_up:List[Individual], thumbs_down:List[Individual], added_songs:List[Individual]):
 
339
  added_songs (List[Individual]): List of individuals added to the playlist.
340
  """
341
  new_track_inds = set()
342
+ # Init population distance matrix
343
+ distance_matrix = np.zeros((population.size, population.size))
344
  for i in range(population.size):
345
  if thumbs_down:
346
  disliked_track = choice(thumbs_down)
 
362
  gene_distances = attracting_track.genome - disliked_track.genome
363
  resulting_genome = seed_track.genome + gene_distances*population.mutation_size
364
  child = get_closest_song_to_genome(population, resulting_genome, new_track_inds)
365
+ # Record distance vector for parent-child.
366
+ distance_matrix[i, :] = child.genome - attracting_track.genome
367
  population.pop[i] = child
368
+ # Add to distance matrix tracking list.
369
+ population.distance_matrices.append(distance_matrix)