def main(): # create object instances print("Preparing to start...") print("Number of clusters: " + sys.argv[1]) db = Database(None) df = Dataframe(None) n_clusters = int(sys.argv[1]) cluster = Clustering(n_clusters if n_clusters else 1) # do db setup before starting (optional) cleandb = True if cleandb: db.clear("tcc", "processed") try: # get data print("Step 1/3 - Fetching and formatting...") to_cluster = {} rs = db.doQuery("tcc", "online_retail", to_cluster) # convert to dataframe and format orders = df.createDf(rs) orders = df.deleteCol(orders, "_id") # orders = df.deleteCol(orders, "avgQty") orders = df.convertDf(orders, "int32") #clusterize print("Step 2/3 - Clustering...") results = cluster.doKmeans(orders) # add clusterization results to dataset and save print("Step 3/3 - Preparing and saving...") orders = df.addCol(orders, "cluster", results["yhat"]) orders_json = df.toJson(orders, False) result = db.insertMany("tcc", "processed", orders_json) print("Done!") print(result) except Exception as ex: print("An error has occured!") print(ex)
class Amity: '''This class creates rooms, adds people and randomly allocates people to the rooms''' rooms = [] # list of rooms in amity people = [] # list of people in amity def __init__(self, database=None): '''Initialize this class with a database or let the class create one automatically''' self.database = Database(database) def room_exists(self, name): '''Check that a room with the specified name exists''' if self.rooms: for room in self.rooms: if name == room['name']: return room return None def create_room(self, room_type, room_name): """Create a new room in amity""" try: if not isinstance(room_type, str) or not \ isinstance(room_name, str): raise ValueError('Room name and type must be a string and ' + 'not an integer or float!') elif room_type.lower() not in ('livingspace', 'office'): raise ValueError('Room type is incorrect. Must be office or ' + 'livingspace!') elif not room_name.isalpha(): raise ValueError( 'Room name cannot be empty or have special ' + 'characters.\n{} is not a valid name!\n'.format(room_name)) if self.room_exists(room_name): raise ValueError( 'Room with name {} already exists!'.format(room_name)) elif room_type == 'office': return self.create_office(room_name) elif room_type == 'livingspace': return self.create_livingspace(room_name) except Exception: raise def create_livingspace(self, name): """Create a new livingspace in amity""" livingspace = LivingSpace(name) self.rooms.append(livingspace.__dict__) return colored('Livingspace {} created.'.format(name), 'white', 'on_green') def create_office(self, name): """Create a new office in amity""" office = Office(name) self.rooms.append(office.__dict__) return colored('Office {} created.'.format(name), 'white', 'on_green') def allocate_person(self, person_name): '''Allocate a person randomly to a room''' person = self.person_exists(person_name) try: if person: room = self.get_room(person=person_name) if room: if 'wants_livingspace' in person.keys() and \ len(room) == 1: # check if fellow who wants livingspace and was only # allocated one room and allocate the other room # now that it's available if room[0]['room_type'] != 'livingspace': return self.allocate_livingspace(person_name) else: return self.allocate_office(person_name, 'fellow') raise ValueError( '{} already allocated a space!'.format(person_name)) elif person['person_type'] == 'staff': return self.allocate_office(person_name, 'staff') elif 'wants_livingspace' in person.keys(): result = self.allocate_office(person_name, 'fellow') + \ '\n' + self.allocate_livingspace(person_name) return result return self.allocate_office(person_name, 'fellow') else: raise ValueError( "Person {} doesn't exist!".format(person_name)) except ValueError: raise def allocate_livingspace(self, name): """Allocate livingspace to fellows.""" rooms = self.get_room(available_rooms='livingspace') if not rooms: return colored( 'There are no available livingspaces to allocate {}!'.format( name), 'white', 'on_red') else: room = random.choice(rooms) room['occupants'].append(name) return colored( 'Fellow {} allocated space in livingspace {}.'.format( name, room['name']), 'white', 'on_green') def allocate_office(self, name, person_type): """Allocate office to staff or fellow.""" rooms = self.get_room(available_rooms='office') if not rooms: return colored( 'There are no available offices to allocate {}!'.format(name), 'white', 'on_red') else: room = random.choice(rooms) room['occupants'].append(name) return colored( '{} {} allocated space in office {}.'.format( person_type.capitalize(), name, room['name']), 'white', 'on_green') def get_room(self, room_type=None, room_name=None, available_rooms=None, person=None): """Get a list of specific rooms in amity depending on room type, name availability or occupants""" if room_name: return [room for room in self.rooms if room['name'] == room_name][0] elif room_type: return [ room for room in self.rooms if room['room_type'] == room_type ] elif available_rooms: return [ room for room in self.rooms if self.check_room_availability(room['name']) and room['room_type'] == available_rooms ] elif person: return [room for room in self.rooms if person in room['occupants']] return None def check_room_availability(self, room_name): """Check for the availability of a specific room in amity""" if self.room_exists(room_name): room = self.get_room(room_name=room_name) return room['max_space'] - len(room['occupants']) else: return colored("Room {} doesn't exist!".format(room_name), 'white', 'on_red') def person_exists(self, name): """Check if a person exists in amity""" if self.people: for person in self.people: if name == person['name']: return person return None def remove_person_from_room(self, person_name, office=None, livingspace=None): '''Remove a person from all assigned rooms in amity''' if office: rooms = [ room for room in self.rooms if person_name in room['occupants'] and room['room_type'] == 'office' ] elif livingspace: rooms = [ room for room in self.rooms if person_name in room['occupants'] and room['room_type'] == 'livingspace' ] else: rooms = [ room for room in self.rooms if person_name in room['occupants'] ] if rooms: for room in rooms: room['occupants'].remove(person_name) cprint( '{} removed successfully from {} {}.'.format( person_name.capitalize(), room['room_type'], room['name']), 'white', 'on_green') else: cprint( "{} isn't allocated or is not assigned to the specified room!". format(person_name.capitalize()), 'white', 'on_red') def remove_person(self, name): '''Remove a person completely from amity''' try: if self.person_exists(name): self.people.remove(self.person_exists(name)) self.remove_person_from_room(name) return colored('Person {} removed.'.format(name), 'white', 'on_green') else: raise ValueError("Person {} doesn't exist!".format(name)) except ValueError: raise def reallocate_person(self, person_name, room_name): """Reallocate an employee from one room to another""" try: if self.room_exists(room_name): room = self.get_room(room_name=room_name) room_type = room['room_type'] else: raise ValueError("Room {} doesn't exist!".format(room_name)) # check if that person exists person = self.person_exists(person_name) if not person: raise ValueError("Person {} doesn't exist!".format(person)) # validate staff isn't allocated to livingspace elif (person['person_type'] == 'staff' and room_type == 'livingspace'): raise ValueError( 'Staff {} cannot be allocated livingspace!'.format( person_name)) # validate fellow who doesn't want livingspace isn't # allocated livingspace elif (person['person_type'] == 'fellow' and room_type == 'livingspace' and 'wants_livingspace' not in person.keys()): raise ValueError('Fellow {} cannot be '.format(person_name) + 'allocated livingspace as they opted out!') else: return self.reallocate(person['name'], room_type, room_name) except ValueError: raise def reallocate(self, person_name, room_type, room_name): '''Helper function to reallocating person''' room = [ room for room in self.rooms if person_name in room['occupants'] and room['room_type'] == room_type ] if not room: raise ValueError('Allocate {} to {} first!'.format( room_type, person_name)) room = room[0] # check if reallocating to same room if room['name'] == room_name: raise ValueError('{} is already allocated to {} {}!'.format( person_name.capitalize(), room_type, room_name)) if self.check_room_availability(room_name): self.get_room(room_name=room_name)['occupants'].append(person_name) room['occupants'].remove(person_name) return colored( '{} reallocated to {} {}.'.format(person_name.capitalize(), room_type, room_name), 'white', 'on_green') else: raise ValueError('{} {} has maximum number of occupants!'.format( room_type.capitalize(), room_name)) def load_rooms(self, filename): """Load rooms from a file.""" with open(filename, 'r') as file: lines = list(line for line in (l.rstrip() for l in file) if line) for line in lines: line = line.lower().split() names = [ name for name in line if name not in ('office', 'livingspace') ] room_type = ' '.join([ room for room in line if room in ('office', 'livingspace') ]) try: for name in names: print(self.create_room(room_type, name)) except Exception as error: cprint(error, 'white', 'on_red') return colored('Rooms loaded from {} successfully.'.format(filename), 'white', 'on_green') def load_people(self, filename): """Load people from a file.""" with open(filename, 'r') as file: lines = list(line for line in (l.rstrip() for l in file) if line) for line in lines: line = line.lower().split() name = ' '.join([ name for name in line if name not in ('fellow', 'staff', 'y', 'yes') ]) role = ' '.join( [role for role in line if role in ('staff', 'fellow')]) want_livingspace = [ space for space in line if space in ('y', 'yes') ] try: if want_livingspace: print(self.add_person(role, name, True)) else: print(self.add_person(role, name)) except Exception as error: cprint(error, 'white', 'on_red') return colored('People loaded from {} successfully.'.format(filename), 'white', 'on_green') def print_allocations(self, filename=None): """Print out the allocated rooms""" allocations = { room['name']: [room['room_type'], room['occupants']] for room in self.rooms if room['occupants'] } result = '' if not allocations: result = '\nALLOCATIONS\n' + '-'*20+'\n' +\ colored('NO ALLOCATIONS HAVE BEEN DONE YET', 'white', 'on_red') for name, details in allocations.items(): persons = '' for person in details[1]: persons += person.upper() + ', ' # persons[:-2] to strip out the last comma result += '{} ({})\n'.format(name.upper(), details[0].upper()) + \ '-'*20+' \n{}\n\n'.format(persons[:-2]) if not filename: return result with open(filename, 'w') as file: file.writelines(result) return colored( 'Allocations have been saved to file {}.'.format(filename), 'white', 'on_green') def print_unallocated(self, filename=None): """Print out the unallocations in amity""" allocated = {} for room in self.rooms: for person in room['occupants']: if person not in allocated.keys(): allocated[person] = [] if room['room_type'] not in allocated[person]: allocated[person].append(room['room_type']) # label fellow who wants livingspace but without livingspace # as unallocated to livingspace or office unallocated = [ person['name'] for person in self.people if person['name'] not in allocated.keys() ] for person, details in allocated.items(): person = self.person_exists(person) if 'wants_livingspace' in person.keys(): if len(details) == 1 and details[0] == 'office': unallocated.append('{} (not allocated livingspace)'.format( person['name'])) elif len(details) == 1 and details[0] == 'livingspace': unallocated.append('{} (not allocated office)'.format( person['name'])) result = '\nUNALLOCATED\n' + '-' * 20 + '\n' if not unallocated: result += colored('NO UNALLOCATED PEOPLE', 'white', 'on_red') else: for person in unallocated: result += '{}\n'.format(person.upper()) if not filename: return result with open(filename, 'w') as file: file.writelines(result) return colored( 'Unallocations have been saved to file {}.'.format(filename), 'white', 'on_green') def print_room(self, room_name): """Print the people in a specific room in amity""" try: if self.room_exists(room_name): people = [[people.upper() for people in room['occupants']] for room in self.rooms if room['name'] == room_name][0] if not people: raise ValueError( 'No one has been assigned to {} yet!'.format( room_name)) else: return ', '.join(people) raise ValueError('No such room as {} in amity!'.format(room_name)) except ValueError: raise def add_person(self, role, person_name, wants_livingspace=False): """Add a new person in amity""" try: if role.lower() not in ('staff', 'fellow'): raise ValueError( 'Person role is incorrect. Should be fellow or staff!') elif self.person_exists(person_name): raise ValueError( 'Person {} already exists!'.format(person_name)) else: role = role.lower() person_name = person_name.lower() # ensure that name contains only alphabetic chars if not ''.join(person_name.split()).isalpha(): raise ValueError( 'Name must be alphabetic chars. {} is incorrect!'. format(person_name)) elif role == 'staff' and wants_livingspace: self.add_staff(person_name) result = colored('Staff cannot be assigned livingspace!', 'white', 'on_red') result += colored( '\n{} {} added.'.format(role.capitalize(), person_name), 'white', 'on_green') return result elif role == 'staff': self.add_staff(person_name) return colored( '{} {} added.'.format(role.capitalize(), person_name), 'white', 'on_green') elif role == 'fellow': self.add_fellow(person_name, wants_livingspace) return colored( '{} {} added.'.format(role.capitalize(), person_name), 'white', 'on_green') except ValueError: raise def add_fellow(self, person_name, wants_livingspace): '''Add a fellow to amity''' if wants_livingspace: self.people.append(Fellow(person_name, True).__dict__) print(self.allocate_livingspace(person_name)) else: self.people.append(Fellow(person_name).__dict__) print(self.allocate_office(person_name, 'fellow')) def add_staff(self, person_name): '''Add a staff to amity''' self.people.append(Staff(person_name).__dict__) print(self.allocate_office(person_name, 'staff')) def save_state(self, database=None): """Save the current state of amity to the database""" self.database.clear() self.database.initialize(database) print(self.save_people()) print(self.save_rooms()) self.database.save() return colored("Amity's state saved successfully.", 'white', 'on_green') def save_rooms(self): '''Save the current state of rooms in amity to the database''' for room in self.rooms: people = [] # hold the people objects from db query on person name for occupant in room['occupants']: occupant = occupant.split() person = self.database.session.query(Person).filter_by( first_name=occupant[0], last_name=occupant[1]).first() people.append(person) room_to_save = Room(name=room['name'], type=room['room_type'], max_space=room['max_space'], occupants=people) self.database.session.add(room_to_save) return colored('Rooms in amity saved successfully.', 'white', 'on_green') def save_people(self): '''Save the current state of people in amity to the database''' for person in self.people: person_name = person['name'].split() first_name = person_name[0] last_name = person_name[1] wants_livingspace = person['wants_livingspace'] if\ 'wants_livingspace' in person.keys() else False person_to_save = Person(first_name=first_name, last_name=last_name, role=person['person_type'], wants_livingspace=wants_livingspace) self.database.session.add(person_to_save) return colored('People in amity saved successfully.', 'white', 'on_green') def load_state(self, database=None): """Load amity resources from the database""" self.database.initialize(database) amity_rooms = self.database.session.query(Room).all() print(self.rooms_load(amity_rooms)) people = self.database.session.query(Person).all() print(self.people_load(people)) return colored("Amity's previous state loaded successfully.", 'white', 'on_green') def rooms_load(self, amity_rooms): '''Load rooms from the database to amity''' for room in amity_rooms: room_dict = { 'name': room.name, 'room_type': room.type, 'max_space': room.max_space, 'occupants': [] } if not self.room_exists(room.name): self.rooms.append(room_dict) else: cprint( '{} {} already exists in amity!'.format( room.type.capitalize(), room.name), 'white', 'on_red') return colored('Rooms loaded successfully.', 'white', 'on_green') def people_load(self, people): '''Load people from the database to amity''' for person in people: person_name = person.first_name + ' ' + person.last_name if not self.person_exists(person_name): if person.wants_livingspace: person_dict = { 'name': person_name, 'person_type': person.role, 'wants_livingspace': True } else: person_dict = { 'name': person_name, 'person_type': person.role } self.people.append(person_dict) self.load_person_to_rooms(person) else: cprint( '{} {} already exists in amity!'.format( person.role.capitalize(), person_name), 'white', 'on_red') return colored('People loaded successfully.', 'white', 'on_green') def load_person_to_rooms(self, person): '''Load people into rooms from the previous states allocation''' person_name = person.first_name + ' ' + person.last_name for person_room in person.room: for room in self.rooms: if room['name'] == person_room.name: if person_name not in room['occupants']: room['occupants'].append(person_name) else: cprint( '{} already assigned to {} {}!'.format( person_name.capitalize(), room['room_type'], room['name']), 'white', 'on_red')