Now we try to build a supervised learner to locate pokemons given some distance levels and rankings inputs at several locations. First let us look at the most simple case - unordered, fixed-length inputs. The output in the case will be the estimated locations of each pokemons.


In [4]:
import numpy as np
import matplotlib.pyplot as plt
import random
import pandas as pd
import matplotlib.patches as patches
from scipy.stats import gennorm
from scipy.stats import gamma
from IPython import display
import pickle
%matplotlib inline

In [5]:
# borrowed helper functions

def generate_initial_coordinates(side_length=2000, n_pokemon=9):
    pokemons = {}
    for i in range(n_pokemon):
        pokemons[i] = np.array([random.uniform(-side_length/2, side_length/2),
                                random.uniform(-side_length/2, side_length/2)])
    return pokemons

def distance(coord1, coord2):
    return np.sqrt((coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2)

# this is not visible to players
def pokemon_distances(player_coord, pokemons):
    return {i: distance(player_coord, coord) for i, coord in pokemons.items()}

def rank(input):
    output = [0] * len(input)
    for i, x in enumerate(sorted(range(len(input)), key=lambda y: input[y])):
        output[x] = i
    return output

# player will be able to see this
# slight bug - we will not be able to see rankings of pokemons that are 
# out of radar radius (but we can fix this later)
# def pokemon_rankings(player_coord, pokemons):
#     dists = pokemon_distances(player_coord, pokemons)
#     rankings = {}
#     for i, x in enumerate(sorted(range(len(dists)), key=lambda y: dists[y])):
#         rankings[x] = i
#     return rankings

def pokemon_rankings(player_coord, pokemons):
    dists = pokemon_distances(player_coord, pokemons)
    return {i: v for i, v in zip( dists.keys(), np.argsort(np.argsort(list(dists.values()))) )}

def plot_pokemons(player_coord, pokemons, xylim=(-1100, 1100)):
    plt.figure(figsize=(15,15))
    # non-target pokemons
    plt.scatter([x - player_coord[0] for x, y in [coord for coord in pokemons.values()]][1:], 
                [y - player_coord[1] for x, y in [coord for coord in pokemons.values()]][1:])
    # target pokemon
    plt.scatter([x - player_coord[0] for x, y in [coord for coord in pokemons.values()]][0], 
                [y - player_coord[1] for x, y in [coord for coord in pokemons.values()]][0],
               marker="*", color='red', s=15)
    plt.axes().set_aspect(1)
    plt.axes().set_xlim(xylim)
    plt.axes().set_ylim(xylim)
    # player
    plt.scatter(0, 0 , color='purple', s=15)
    # detection radii
    dists = {10:'green', 25:'blue', 100:'yellow', 1000:'red'}
    for r in dists:
        plt.axes().add_patch(plt.Circle((0,0), r, fill=False, color=dists[r]))
    plt.show()
    
def footprint(distance):
    if distance < 10:
        return 0
    elif distance < 25:
        return 1
    elif distance < 100:
        return 2
    elif distance < 1000:
        return 3
    else:
        return 5

def distance_levels(player_coord, pokemons):
    dists = pokemon_distances(player_coord, pokemons)
    return {i: footprint(v) for i,v in dists.items()}

def distance_levels_and_rankings(player_coord, pokemons):
    dists = pokemon_distances(player_coord, pokemons)
    return {i: footprint(v) for i,v in dists.items()}, {i: v for i, v in 
                                                        zip(dists.keys(), 
                                                            np.argsort(np.argsort(list(dists.values()))))}

def make_rand_vector(dims):
    vec = np.array([random.gauss(0, 1) for i in range(dims)])
    mag = np.linalg.norm(vec)
    return vec / mag

In [6]:
# training example generator
def generate_training_examples(radius=1000, n_points=30):
    pokemons = generate_initial_coordinates(side_length=2000, n_pokemon=9)
    samples = pd.DataFrame(columns=['player_coord', 'levels', 'rankings'])
    for i in range(n_points):
        point_distance = random.random() * radius
        point_angle = random.random() * np.pi * 2
        point = np.array([point_distance * np.cos(point_angle), point_distance * np.sin(point_angle)])
        levels, rankings = distance_levels_and_rankings(point, pokemons)
        samples.loc[i] = [point, levels, rankings]
    return samples, pokemons

In [7]:
s, p = generate_training_examples()
s


Out[7]:
player_coord levels rankings
0 [-469.642073482, 391.305413414] {0: 5, 1: 5, 2: 3, 3: 5, 4: 3, 5: 5, 6: 3, 7: ... {0: 5, 1: 6, 2: 1, 3: 3, 4: 2, 5: 4, 6: 0, 7: ...
1 [50.9549076837, 483.512772018] {0: 5, 1: 5, 2: 3, 3: 3, 4: 3, 5: 3, 6: 2, 7: ... {0: 7, 1: 6, 2: 3, 3: 2, 4: 1, 5: 4, 6: 0, 7: ...
2 [818.227492821, 450.670091912] {0: 5, 1: 5, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 7, 1: 5, 2: 6, 3: 0, 4: 1, 5: 4, 6: 3, 7: ...
3 [-175.395997912, 123.985966341] {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 7, 1: 5, 2: 4, 3: 3, 4: 1, 5: 2, 6: 0, 7: ...
4 [9.37804343665, 10.109147277] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 6, 1: 5, 2: 7, 3: 3, 4: 0, 5: 2, 6: 1, 7: ...
5 [244.966666706, -604.354898897] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 5, 7: ... {0: 3, 1: 0, 2: 8, 3: 4, 4: 5, 5: 1, 6: 7, 7: ...
6 [-454.865946187, 43.6967178746] {0: 3, 1: 5, 2: 3, 3: 5, 4: 3, 5: 3, 6: 3, 7: ... {0: 2, 1: 5, 2: 3, 3: 7, 4: 1, 5: 4, 6: 0, 7: ...
7 [-23.5482910721, -690.843739649] {0: 3, 1: 3, 2: 5, 3: 5, 4: 5, 5: 3, 6: 5, 7: ... {0: 1, 1: 0, 2: 8, 3: 6, 4: 5, 5: 2, 6: 7, 7: ...
8 [-50.8400634789, -47.3302079241] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 6, 1: 4, 2: 7, 3: 3, 4: 0, 5: 2, 6: 1, 7: ...
9 [486.432704901, 704.293615562] {0: 5, 1: 5, 2: 5, 3: 3, 4: 3, 5: 5, 6: 3, 7: ... {0: 7, 1: 6, 2: 5, 3: 1, 4: 0, 5: 4, 6: 2, 7: ...
10 [99.5739868835, 841.597458818] {0: 5, 1: 5, 2: 3, 3: 3, 4: 3, 5: 5, 6: 3, 7: ... {0: 7, 1: 6, 2: 3, 3: 2, 4: 1, 5: 4, 6: 0, 7: ...
11 [7.80197588571, 5.58551184113] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 6, 1: 5, 2: 7, 3: 3, 4: 0, 5: 2, 6: 1, 7: ...
12 [153.17190599, -49.7808455248] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 6, 1: 5, 2: 7, 3: 2, 4: 1, 5: 0, 6: 3, 7: ...
13 [-79.5588638246, 819.481347184] {0: 5, 1: 5, 2: 3, 3: 3, 4: 3, 5: 5, 6: 3, 7: ... {0: 7, 1: 6, 2: 2, 3: 3, 4: 1, 5: 4, 6: 0, 7: ...
14 [297.874314923, 552.907255778] {0: 5, 1: 5, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 7, 1: 6, 2: 5, 3: 2, 4: 0, 5: 4, 6: 1, 7: ...
15 [112.483282456, -36.4540742267] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 6, 1: 5, 2: 7, 3: 3, 4: 0, 5: 1, 6: 2, 7: ...
16 [14.1305652516, -178.395919669] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 6, 1: 2, 2: 8, 3: 5, 4: 1, 5: 0, 6: 3, 7: ...
17 [97.4916516876, 42.2972928045] {0: 5, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 6, 1: 5, 2: 7, 3: 3, 4: 0, 5: 2, 6: 1, 7: ...
18 [-389.748335739, -16.3470414836] {0: 3, 1: 3, 2: 3, 3: 5, 4: 3, 5: 3, 6: 3, 7: ... {0: 2, 1: 4, 2: 5, 3: 7, 4: 1, 5: 3, 6: 0, 7: ...
19 [75.838928213, 660.776286045] {0: 5, 1: 5, 2: 3, 3: 3, 4: 3, 5: 5, 6: 3, 7: ... {0: 7, 1: 6, 2: 3, 3: 2, 4: 1, 5: 4, 6: 0, 7: ...
20 [-731.175249728, 64.9557561487] {0: 3, 1: 5, 2: 3, 3: 5, 4: 5, 5: 5, 6: 3, 7: ... {0: 2, 1: 5, 2: 0, 3: 7, 4: 3, 5: 6, 6: 1, 7: ...
21 [-110.97780788, 74.7736510168] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 6, 1: 5, 2: 7, 3: 3, 4: 1, 5: 2, 6: 0, 7: ...
22 [287.831491954, 921.387898823] {0: 5, 1: 5, 2: 5, 3: 3, 4: 3, 5: 5, 6: 3, 7: ... {0: 7, 1: 6, 2: 3, 3: 2, 4: 1, 5: 5, 6: 0, 7: ...
23 [-180.173968612, -95.4890893136] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 4, 1: 3, 2: 8, 3: 5, 4: 0, 5: 2, 6: 1, 7: ...
24 [-689.475065951, -399.745157415] {0: 3, 1: 3, 2: 5, 3: 5, 4: 5, 5: 5, 6: 5, 7: ... {0: 0, 1: 2, 2: 6, 3: 8, 4: 5, 5: 3, 6: 4, 7: ...
25 [-162.072358777, 142.603302258] {0: 5, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 7, 1: 6, 2: 4, 3: 3, 4: 1, 5: 2, 6: 0, 7: ...
26 [-218.492935418, 442.898609167] {0: 5, 1: 5, 2: 3, 3: 3, 4: 3, 5: 5, 6: 3, 7: ... {0: 6, 1: 7, 2: 2, 3: 3, 4: 1, 5: 4, 6: 0, 7: ...
27 [135.775333016, -798.109346798] {0: 3, 1: 2, 2: 5, 3: 5, 4: 5, 5: 3, 6: 5, 7: ... {0: 2, 1: 0, 2: 8, 3: 5, 4: 6, 5: 1, 6: 7, 7: ...
28 [-131.489623254, 207.002071361] {0: 5, 1: 5, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 7, 1: 6, 2: 4, 3: 2, 4: 1, 5: 3, 6: 0, 7: ...
29 [-190.227727843, -181.228597694] {0: 3, 1: 3, 2: 5, 3: 3, 4: 3, 5: 3, 6: 3, 7: ... {0: 2, 1: 1, 2: 8, 3: 6, 4: 3, 5: 0, 6: 4, 7: ...

In [8]:
def flatten_training_example(samples, n_pokemons=9, radius=1000):
    flat = pd.DataFrame({'pX': samples['player_coord'].apply(lambda x: x[0] / radius), 
                         'pY': samples['player_coord'].apply(lambda x: x[1] / radius)})
    for i in range(n_pokemons):
        flat['lv' + str(i)] = samples['levels'].apply(lambda x: x[i])
        flat['rg' + str(i)] = samples['rankings'].apply(lambda x: x[i])
    return flat

In [9]:
flatten_training_example(s)


Out[9]:
pX pY lv0 rg0 lv1 rg1 lv2 rg2 lv3 rg3 lv4 rg4 lv5 rg5 lv6 rg6 lv7 rg7 lv8 rg8
0 -0.469642 0.391305 5 5 5 6 3 1 5 3 3 2 5 4 3 0 5 7 5 8
1 0.050955 0.483513 5 7 5 6 3 3 3 2 3 1 3 4 2 0 3 5 5 8
2 0.818227 0.450670 5 7 5 5 5 6 3 0 3 1 3 4 3 3 3 2 5 8
3 -0.175396 0.123986 3 7 3 5 3 4 3 3 3 1 3 2 3 0 3 6 5 8
4 0.009378 0.010109 3 6 3 5 5 7 3 3 3 0 3 2 3 1 3 4 5 8
5 0.244967 -0.604355 3 3 3 0 5 8 3 4 3 5 3 1 5 7 3 2 5 6
6 -0.454866 0.043697 3 2 5 5 3 3 5 7 3 1 3 4 3 0 5 8 5 6
7 -0.023548 -0.690844 3 1 3 0 5 8 5 6 5 5 3 2 5 7 3 4 3 3
8 -0.050840 -0.047330 3 6 3 4 5 7 3 3 3 0 3 2 3 1 3 5 5 8
9 0.486433 0.704294 5 7 5 6 5 5 3 1 3 0 5 4 3 2 3 3 5 8
10 0.099574 0.841597 5 7 5 6 3 3 3 2 3 1 5 4 3 0 5 5 5 8
11 0.007802 0.005586 3 6 3 5 5 7 3 3 3 0 3 2 3 1 3 4 5 8
12 0.153172 -0.049781 3 6 3 5 5 7 3 2 3 1 3 0 3 3 3 4 5 8
13 -0.079559 0.819481 5 7 5 6 3 2 3 3 3 1 5 4 3 0 5 5 5 8
14 0.297874 0.552907 5 7 5 6 5 5 3 2 3 0 3 4 3 1 3 3 5 8
15 0.112483 -0.036454 3 6 3 5 5 7 3 3 3 0 3 1 3 2 3 4 5 8
16 0.014131 -0.178396 3 6 3 2 5 8 3 5 3 1 3 0 3 3 3 4 5 7
17 0.097492 0.042297 5 6 3 5 5 7 3 3 3 0 3 2 3 1 3 4 5 8
18 -0.389748 -0.016347 3 2 3 4 3 5 5 7 3 1 3 3 3 0 5 8 5 6
19 0.075839 0.660776 5 7 5 6 3 3 3 2 3 1 5 4 3 0 5 5 5 8
20 -0.731175 0.064956 3 2 5 5 3 0 5 7 5 3 5 6 3 1 5 8 5 4
21 -0.110978 0.074774 3 6 3 5 5 7 3 3 3 1 3 2 3 0 3 4 5 8
22 0.287831 0.921388 5 7 5 6 5 3 3 2 3 1 5 5 3 0 5 4 5 8
23 -0.180174 -0.095489 3 4 3 3 5 8 3 5 3 0 3 2 3 1 3 6 5 7
24 -0.689475 -0.399745 3 0 3 2 5 6 5 8 5 5 5 3 5 4 5 7 3 1
25 -0.162072 0.142603 5 7 3 6 3 4 3 3 3 1 3 2 3 0 3 5 5 8
26 -0.218493 0.442899 5 6 5 7 3 2 3 3 3 1 5 4 3 0 5 5 5 8
27 0.135775 -0.798109 3 2 2 0 5 8 5 5 5 6 3 1 5 7 3 3 3 4
28 -0.131490 0.207002 5 7 5 6 3 4 3 2 3 1 3 3 3 0 3 5 5 8
29 -0.190228 -0.181229 3 2 3 1 5 8 3 6 3 3 3 0 3 4 3 5 3 7

In [18]:
def random_point(radius=1000):
    point_distance = random.random() * radius
    point_angle = random.random() * np.pi * 2
    return np.array([point_distance * np.cos(point_angle), point_distance * np.sin(point_angle)])

def generate_training_ndarray(radius=500, n_points=50, n_examples=100, n_pokemons=9):
    train = np.ndarray(shape=[n_examples, n_points, 2 + n_pokemons *2])
    train.fill(0)
    target = np.ndarray(shape=[n_examples, n_pokemons, 2])
    for z in range(n_examples):
        pokemons = generate_initial_coordinates(side_length=2000)
        target[z, :, :] = list(pokemons.values())
        for x in range(n_points):
            train[z, x, 0:2] = random_point(radius)
            levels, rankings = distance_levels_and_rankings(train[z, x, 0:2], pokemons)
            train[z, x, 2:11] = list(levels.values())
            train[z, x, 11:] = list(rankings.values())
    return train, target

In [19]:
train, target = generate_training_ndarray(n_examples=100000)

In [20]:
pickle.dump({'train': train, 'target': target}, open('training_data.pickle', 'wb'))

In [21]:
obj = pickle.load(open('training_data.pickle', 'rb'))
obj['train'].shape


Out[21]:
(100000, 50, 20)

In [ ]: