Skip to content
This repository has been archived by the owner on Oct 25, 2024. It is now read-only.

Week09 #174

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions week09/improvement/boids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
A deliberately bad implementation of
[Boids](http://dl.acm.org/citation.cfm?doid=37401.37406)
for use as an exercise on refactoring.

This code simulates the swarming behaviour of bird-like objects ("boids").
"""

from matplotlib import pyplot as plt
from matplotlib import animation

import random

boids_x=[random.uniform(-450,50.0) for x in range(50)]
boids_y=[random.uniform(300.0,600.0) for x in range(50)]
boid_x_velocities=[random.uniform(0,10.0) for x in range(50)]
boid_y_velocities=[random.uniform(-20.0,20.0) for x in range(50)]
boids=(boids_x,boids_y,boid_x_velocities,boid_y_velocities)

def update_boids(boids):
xs,ys,xvs,yvs=boids
# Fly towards the middle
for i in range(len(xs)):
for j in range(len(xs)):
xvs[i]=xvs[i]+(xs[j]-xs[i])*0.01/len(xs)
for i in range(len(xs)):
for j in range(len(xs)):
yvs[i]=yvs[i]+(ys[j]-ys[i])*0.01/len(xs)
# Fly away from nearby boids
for i in range(len(xs)):
for j in range(len(xs)):
if (xs[j]-xs[i])**2 + (ys[j]-ys[i])**2 < 100:
xvs[i]=xvs[i]+(xs[i]-xs[j])
yvs[i]=yvs[i]+(ys[i]-ys[j])
# Try to match speed with nearby boids
for i in range(len(xs)):
for j in range(len(xs)):
if (xs[j]-xs[i])**2 + (ys[j]-ys[i])**2 < 10000:
xvs[i]=xvs[i]+(xvs[j]-xvs[i])*0.125/len(xs)
yvs[i]=yvs[i]+(yvs[j]-yvs[i])*0.125/len(xs)
# Move according to velocities
for i in range(len(xs)):
xs[i]=xs[i]+xvs[i]
ys[i]=ys[i]+yvs[i]
32 changes: 32 additions & 0 deletions week09/improvement/clustering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""This code implements the k-means clustering algorithm for 2 dimensions."""

from math import *
from random import *

k=3

lines = open('samples.csv', 'r').readlines()
ps=[]
for line in lines: ps.append(tuple(map(float, line.strip().split(','))))

m=[ps[randrange(len(ps))], ps[randrange(len(ps))], ps[randrange(len(ps))]]

alloc=[None]*len(ps)
n=0
while n<10:
for i in range(len(ps)):
p=ps[i]
d=[None] * 3
d[0]=sqrt((p[0]-m[0][0])**2 + (p[1]-m[0][1])**2)
d[1]=sqrt((p[0]-m[1][0])**2 + (p[1]-m[1][1])**2)
d[2]=sqrt((p[0]-m[2][0])**2 + (p[1]-m[2][1])**2)
alloc[i]=d.index(min(d))
for i in range(3):
alloc_ps=[p for j, p in enumerate(ps) if alloc[j] == i]
new_mean=(sum([a[0] for a in alloc_ps]) / len(alloc_ps), sum([a[1] for a in alloc_ps]) / len(alloc_ps))
m[i]=new_mean
n=n+1

for i in range(3):
alloc_ps=[p for j, p in enumerate(ps) if alloc[j] == i]
print("Cluster " + str(i) + " is centred at " + str(m[i]) + " and has " + str(len(alloc_ps)) + " points.")
17 changes: 17 additions & 0 deletions week09/improvement/trees.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""This code produces a tree-like plot."""

from math import sin, cos
from matplotlib import pyplot as plt
s=1
d=[[0,1,0]]
plt.plot([0,0],[0,1])
for i in range(5):
n=[]
for j in range(len(d)):
n.append([d[j][0]+s*sin(d[j][2]-0.1), d[j][1]+s*cos(d[j][2]-0.1), d[j][2]-0.1])
n.append([d[j][0]+s*sin(d[j][2]+0.1), d[j][1]+s*cos(d[j][2]+0.1), d[j][2]+0.1])
plt.plot([d[j][0], n[-2][0]],[d[j][1], n[-2][1]])
plt.plot([d[j][0], n[-1][0]],[d[j][1], n[-1][1]])
d=n
s*=0.6
plt.savefig('tree.png')
61 changes: 61 additions & 0 deletions week09/refactoring/initial_global.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
def average_age():
"""Compute the average age of the group's members."""
all_ages = [person["age"] for person in group.values()]
return sum(all_ages) / len(group)


def forget(person1, person2):
"""Remove the connection between two people."""
group[person1]["relations"].pop(person2, None)
group[person2]["relations"].pop(person1, None)


def add_person(name, age, job, relations):
"""Add a new person with the given characteristics to the group."""
new_person = {
"age": age,
"job": job,
"relations": relations
}
group[name] = new_person


group = {
"Jill": {
"age": 26,
"job": "biologist",
"relations": {
"Zalika": "friend",
"John": "partner"
}
},
"Zalika": {
"age": 28,
"job": "artist",
"relations": {
"Jill": "friend",
}
},
"John": {
"age": 27,
"job": "writer",
"relations": {
"Jill": "partner"
}
}
}

nash_relations = {
"John": "cousin",
"Zalika": "landlord"
}

add_person("Nash", 34, "chef", nash_relations)

forget("Nash", "John")

if __name__ == "__main__":
assert len(group) == 4, "Group should have 4 members"
assert average_age() == 28.75, "Average age of the group is incorrect!"
assert len(group["Nash"]["relations"]) == 1, "Nash should only have one relation"
print("All assertions have passed!")
44 changes: 44 additions & 0 deletions week09/refactoring/initial_person_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
class Person:
"""A class to represent an individual and their connections."""

def __init__(self, name, age, job):
"""Create a new Person with the given name, age and job and no connections."""
self.name = name
self.age = age
self.job = job
self.connections = dict()

def add_connection(self, person, relation):
"""Add a new connection to a person"""
if person in self.connections:
raise ValueError(f"I already know about {person.name}")
self.connections[person] = relation

def forget(self, person):
"""Removes any connections to a person"""
pass


def average_age(group):
"""Compute the average age of the group's members."""
all_ages = [person.age for person in group]
return sum(all_ages) / len(group)


if __name__ == "__main__":
# ...then create the group members one by one...
jill = Person("Jill", 26, "biologist")

# ...then add the connections one by one...
# Note: this will fail from here if the person objects aren't created
jill.add_connection(zalika, "friend")

# ... then forget Nash and John's connection
nash.forget(john)
# Then create the group
my_group = {jill, zalika, john, nash}

assert len(my_group) == 4, "Group should have 4 members"
assert average_age(my_group) == 28.75, "Average age of the group is incorrect!"
assert len(nash.connections) == 1, "Nash should only have one relation "
print("All assertions have passed!")
66 changes: 66 additions & 0 deletions week09/refactoring/initial_two_classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
class Person:
"""A class to represent an individual."""

def __init__(self, name, age, job):
"""Create a new Person with the given name, age and job."""
self.name = name
self.age = age
self.job = job


class Group:
"""A class that represents a group of individuals and their connections."""

def __init__(self):
"""Create an empty group."""
self.members = []
self.connections = {}

def size(self):
"""Return how many people are in the group."""
pass

def contains(self, name):
"""Check whether the group contains a person with the given name.
Useful to throw errors if we try to add a person who already exists or forget someone.
"""
return any(member.name == name for member in self.members)

def add_person(self, name, age, job):
"""Add a new person with the given characteristics to the group."""
self.members.append(Person(name, age, job))

def number_of_connections(self, name):
"""Find the number of connections that a person in the group has"""
pass

def connect(self, name1, name2, relation, reciprocal=True):
"""Connect two given people in a particular way.
Optional reciprocal: If true, will add the relationship from name2 to name 1 as well
"""
pass

def forget(self, name1, name2):
"""Remove the connection between two people."""
pass

def average_age(self):
"""Compute the average age of the group's members."""
all_ages = [person.age for person in self.members]
return sum(all_ages) / self.size()


if __name__ == "__main__":
# Start with an empty group...
my_group = Group()
# ...then add the group members one by one...
my_group.add_person("Jill", 26, "biologist")
# ...then their connections
my_group.connect("Jill", "Zalika", "friend")
# ... then forget Nash and John's connection
my_group.forget("Nash", "John")

assert my_group.size() == 4, "Group should have 4 members"
assert my_group.average_age() == 28.75, "Average age of the group is incorrect!"
assert my_group.number_of_connections("Nash") == 1, "Nash should only have one relation"
print("All assertions have passed!")
11 changes: 11 additions & 0 deletions week09/versions/version1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from visualisation import *
from processing import *

fs = ['81500.tab', '48151.tab', '62342.tab']
R=[]
R.append(analyse(preprocess(load(fs[0]),0.3)))
R.append(analyse(preprocess(load(fs[1]),0.3)))
R.append(analyse(preprocess(load(fs[2]),0.3)))

for i in range(3):
save_figure(fu_map(R[i]))
30 changes: 30 additions & 0 deletions week09/versions/version2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'''Analysis script for some DSEA measurements.'''

import os

from processing import analyse, is_valid, load, preprocess
from visualisation import fu_map, save_figure


def extract_mean(data_file):
"""Load a dataset, smooth it and run the analysis algorithm on it.

:param data_file: input file containing raw data from an experiment.
"""
assert os.path.exists(data_file), f"File not found: {data_file}"
assert is_valid(data_file), f"File {data_file} not in DSEA format."
data = load(data_file)
# This smoothing is necessary to avoid singular behaviour, see Kim (2012)
scaling = 0.3 # scaling factor to apply, from Reyes & Pace (2004)
smoothed_data = preprocess(data, scaling)
return analyse(smoothed_data)


if __name__ == "__main__":
# The files from my last 3 experiments.
# Note that we can't run this on the data from the MT-3 because the
# files lack the header!
raw_files = ['81500.tab', '48151.tab', '62342.tab']
results = [extract_mean(input_file) for input_file in raw_files]
for result in results:
save_figure(fu_map(result))