Example #1
0
    def test_chunk_halfcourt(self):
        # 1) check if all event satisfies required length
        event_length_th = 30
        for e in self.event_dfs:
            result, _ = preprocessing.remove_non_eleven(e,
                                                        event_length_th,
                                                        verbose=True)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_shotclock(e,
                                                   event_length_th,
                                                   verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_halfcourt(df,
                                                   event_length_th,
                                                   verbose=False)
            result_len = [len(i) for i in result]
            count = sum(np.array(result_len) >= event_length_th)
            self.assertEqual(count, len(result))
            self.assertEqual(type(result[0]), list)

            half_court = 94 / 2.
            for i in result:
                for j in i:
                    # 2) the players must either be on the left court or the right
                    self.assertTrue(
                        sum(np.array(j[5])[1:, 2] >= half_court) == 10
                        or sum(np.array(j[5])[1:, 2] <= half_court) == 10)
    def test_flatten(self):
        half_court = 94/2.
        court_width = 50.
        # corresponding features col index
        player_x_ind = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
        player_y_ind = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
        bball_x_ind = [20]
        bball_y_ind = [21]
        bball_z_ind = [22]
        qtr_ind = [23]
        time_left_ind = [24]
        sc_ind = [25]

        def check_features(f_moment):
            # print(type(f_moment))
            tol = 5.7
            # a) the player positions shall all be greater than zero
            # note: tol here was originally tested for 0, but there can be cases where the player runs off court
            self.assertTrue(sum(f_moment[player_x_ind] >= -tol) == 10 and sum(f_moment[player_x_ind] <= half_court)==10,
                            msg = '\033[91m player x coordinates: {}\033[00m'.format(f_moment[player_x_ind]))
            self.assertTrue(sum(f_moment[player_y_ind] >= -tol) == 10 and sum(f_moment[player_y_ind] <= court_width+tol)==10,
                            msg = '\033[91m player y coordinates: {}\033[00m'.format(f_moment[player_y_ind]))
            # b) bball positions
            self.assertTrue(f_moment[bball_x_ind] >= -tol and f_moment[bball_x_ind] <= half_court + tol, 
                            msg='\033[91m bball x: {}\033[00m'.format(f_moment[bball_x_ind]))
            self.assertTrue(f_moment[bball_y_ind] >= 0 and f_moment[bball_y_ind] <= court_width + tol, 
                            msg='\033[91m bball y: {}\033[00m'.format(f_moment[bball_y_ind]))
            self.assertTrue(f_moment[bball_z_ind] >= 0, msg='bball z: {}'.format(f_moment[bball_z_ind]))
            # c) quarter number
            self.assertTrue(f_moment[qtr_ind] >= 1 and f_moment[qtr_ind] <= 4.,
                            msg='\033[91m quarter number: {}\033[00m'.format(f_moment[qtr_ind]))
            # d) time left to the end of the period in seconds (12 mins per period)
            self.assertTrue(f_moment[time_left_ind] >= 0 and f_moment[sc_ind] <= 12.*60, 
                            msg='\033[91m time left: {}\033[00m'.format(f_moment[time_left_ind]))
            # e) shot clock
            self.assertTrue(f_moment[sc_ind] >= 0 and f_moment[sc_ind] <= 24., 
                            msg='\033[91m shot clock: {}\033[00m'.format(f_moment[sc_ind]))

        event_length_th = 30
        for k, e in enumerate(self.event_dfs):
            result, _ = preprocessing.remove_non_eleven(e, event_length_th, verbose=True)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_shotclock(e, event_length_th, verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_halfcourt(df, event_length_th, verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.reorder_teams(df, self.game_ids[k])
            df = pd.DataFrame({'moments': result})

            flattened, team_ids =  preprocessing.flatten_moments(df)
            # team_id
            # 1) the team_ids should not be the same but share the same several front digits
            [self.assertTrue(team_id[0] != team_id[1], msg='\033[91m team ids: {} | {}\033[00m'.format(team_id[0], team_id[1])) for team_id in team_ids]
            [self.assertTrue(str(team_id[0])[:8] == str(team_id[0])[:8] == '16106127',\
                             msg='\033[91m team ids: {} | {}\033[00m'.format(team_id[0], team_id[1])) for team_id in team_ids]
            # 2) check the values from the features 
            [check_features(j) for i in flattened for j in i]
Example #3
0
    def test_chunk_shotclock(self):
        # 1) check if all event satisfies required length
        event_length_th = 30
        for e in self.event_dfs:
            result, _ = preprocessing.remove_non_eleven(e,
                                                        event_length_th,
                                                        verbose=True)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_shotclock(df,
                                                   event_length_th,
                                                   verbose=False)
            result_len = [len(i) for i in result]
            count = sum(np.array(result_len) >= event_length_th)
            self.assertEqual(count, len(result))
            self.assertEqual(type(result[0]), list)

            for i in result:
                # 2) check if None is in the shot clock from result
                self.assertNotIn(None, [j[3] for j in i])
                # 3) check if the shot clock is in right order
                self.assertTrue(i[0][3] > i[-1][3])
                # 4) check if the first two and last two shotclock value are different
                self.assertTrue(i[0][3] != i[1][3])
                self.assertTrue(i[-1][3] != i[-2][3])
    def test_ohe(self):
        def check_ohe(moments):
            one_hots = moments[:, 129:]
            # each row should only be two 1s from the one hot encoding of two teams
            self.assertEqual(sum(np.sum(one_hots, axis=1) == 2), len(moments))
            # there should be two columns that contain 1s
            self.assertEqual(sum(np.sum(one_hots, axis=0) != 0), 2)

        event_length_th = 30
        for k, e in enumerate(self.event_dfs):
            result, _ = preprocessing.remove_non_eleven(e, event_length_th, verbose=True)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_shotclock(e, event_length_th, verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_halfcourt(df, event_length_th, verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.reorder_teams(df, self.game_ids[k])
            df = pd.DataFrame({'moments': result})

            flattened, team_ids =  preprocessing.flatten_moments(df)
            df = pd.DataFrame({'moments': flattened})

            static_result = preprocessing.create_static_features(df)
            df = pd.DataFrame({'moments': copy.deepcopy(static_result)})
            fs = 1/25.
            dynamic_result = preprocessing.create_dynamic_features(df, fs)

            OHE = preprocessing.OneHotEncoding()
            result = OHE.add_ohs(dynamic_result, team_ids)
            [check_ohe(ms) for ms in result]
    def test_dynamic_features(self):
        def check_dynamics(static_moments, dynamic_moments):
            pxy = static_moments[:, :23]
            next_pxy = copy.deepcopy(pxy[1:, :23])
            fs = 1/25. # time difference between each frame
            vel = ((next_pxy-pxy[:-1])/fs) # we have shifted the velocity to be v2=x2-x1
            vel_list = vel.tolist()
            dynamic_list = dynamic_moments[:, 106:129].tolist()
            self.assertEqual(len(vel_list), len(dynamic_list))
            [self.assertListEqual(vel_list[i], dynamic_list[i]) for i in range(len(vel_list))]

        event_length_th = 30
        for k, e in enumerate(self.event_dfs):
            result, _ = preprocessing.remove_non_eleven(e, event_length_th, verbose=True)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_shotclock(e, event_length_th, verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_halfcourt(df, event_length_th, verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.reorder_teams(df, self.game_ids[k])
            df = pd.DataFrame({'moments': result})

            flattened, _ =  preprocessing.flatten_moments(df)
            df = pd.DataFrame({'moments': flattened})

            static_result = preprocessing.create_static_features(df)
            df = pd.DataFrame({'moments': copy.deepcopy(static_result)})
            fs = 1/25.
            dynamic_result = preprocessing.create_dynamic_features(df, fs)
            self.assertEqual(len(static_result), len(dynamic_result))
            [check_dynamics(static_result[i], dynamic_result[i]) for i in range(len(static_result))]
Example #6
0
    def test_reorder_teams(self):
        # now we want to reorder the team position based on meta data
        court_index = pd.read_csv('../meta_data/court_index.csv')
        court_index = dict(zip(court_index.game_id,
                               court_index.court_position))
        # 1) 42 teams mapping
        self.assertEqual(len(court_index), 42)

        half_court = 94 / 2.
        event_length_th = 25
        for k, e in enumerate(self.event_dfs):
            # remove non eleven
            result, team_ids = preprocessing.remove_non_eleven(e,
                                                               event_length_th,
                                                               verbose=False)
            df = pd.DataFrame({'moments': result})
            # chunk at 24s, None or stopped clocks
            result = preprocessing.chunk_shotclock(e,
                                                   event_length_th,
                                                   verbose=False)
            df = pd.DataFrame({'moments': result})
            # chunk based on half court
            result = preprocessing.chunk_halfcourt(df,
                                                   event_length_th,
                                                   verbose=False)
            df = pd.DataFrame({'moments': result})
            # 2) the homeid is always the first 5 players
            home_id, away_id = team_ids['home_id'], team_ids['away_id']
            for i in result:
                for j in i:
                    self.assertEqual(j[5][1][0], home_id)
                    self.assertEqual(j[5][-1][0], away_id)

            n_events = len(result)
            result = preprocessing.reorder_teams(df, self.game_ids[k])
            df = pd.DataFrame({'moments': result})

            # 3) the returned number of events should not change
            self.assertEqual(n_events, len(result))
            for i in result:
                for j in i:
                    # 4) all players should be already normalized to left half court
                    self.assertEqual(sum(np.array(j[5])[1:, 2] <= half_court),
                                     10)
            # hardcode test cases:
            if k == '0021500196':
                correct = [[1610612761, 2449, 9.8067, 28.92548, 0.0],
                           [1610612761, 201960, 24.3734, 21.43063, 0.0],
                           [1610612761, 200768, 6.86594, 20.4174, 0.0],
                           [1610612761, 201942, 17.89619, 25.21197, 0.0],
                           [1610612761, 202687, 10.1885, 24.11858, 0.0],
                           [1610612746, 1718, 34.33032, 10.36747, 0.0],
                           [1610612746, 200755, 32.26942, 26.02228, 0.0],
                           [1610612746, 101108, 18.86048, 7.87816, 0.0],
                           [1610612746, 201599, 35.95785, 20.65878, 0.0],
                           [1610612746, 201933, 25.66964, 40.3966, 0.0]]
                self.assertListEqual(result[0][0][5][1:], correct)
Example #7
0
 def test_remove_non_eleven(self):
     # 1) check if all event satisfies required length
     event_length_th = 30
     for e in self.event_dfs:
         result, _ = preprocessing.remove_non_eleven(e,
                                                     event_length_th,
                                                     verbose=True)
         result_len = [len(i) for i in result]
         count = sum(np.array(result_len) >= event_length_th)
         self.assertEqual(count, len(result))
         # 2) check type is list
         self.assertEqual(type(result[0]), list)
Example #8
0
    def setUpClass(cls):
        # directories
        main_dir = '../../'
        game_dir = main_dir + 'data/'
        Data = utilities.LoadData(main_dir, game_dir)
        # models_path = './models/'

        cls.game_ids = ['0021500196', '0021500024']
        event_dfs = [
            pd.DataFrame(Data.load_game(g)['events']) for g in cls.game_ids
        ]

        results = []
        hsls = []
        event_length_th = 30
        for k, e in enumerate(event_dfs):
            result, _ = preprocessing.remove_non_eleven(e,
                                                        event_length_th,
                                                        verbose=True)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_shotclock(e,
                                                   event_length_th,
                                                   verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_halfcourt(df,
                                                   event_length_th,
                                                   verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.reorder_teams(df, cls.game_ids[k])
            df = pd.DataFrame({'moments': result})

            flattened, team_ids = preprocessing.flatten_moments(df)
            df = pd.DataFrame({'moments': flattened})

            static_result = preprocessing.create_static_features(df)
            df = pd.DataFrame({'moments': copy.deepcopy(static_result)})
            fs = 1 / 25.
            dynamic_result = preprocessing.create_dynamic_features(df, fs)

            OHE = preprocessing.OneHotEncoding()
            result = OHE.add_ohs(dynamic_result, team_ids)
            df = pd.DataFrame({'moments': result})

            results.append(result)
            hsls.append(hidden_role_learning.HiddenStructureLearning(df))

        cls.results = results
        cls.hsls = hsls
    def test_static_features(self):
        # index related to polar displacement with bball
        r_ball_ind = list(range(26, 36))
        cos_ball_ind = list(range(36, 46))
        sin_ball_ind = list(range(46, 56))
        theta_ball_ind = list(range(56, 66))
        # hoop
        r_hoop_ind = list(range(66, 76))
        cos_hoop_ind = list(range(76, 86))
        sin_hoop_ind = list(range(86, 96))
        theta_hoop_ind = list(range(96, 106))
        diag = np.sqrt(50**2 + 94**2)

        def check_static(f_moment):
            # a1) the player displacements to the ball
            self.assertTrue(sum(f_moment[r_ball_ind] > 0) == 10 and sum(f_moment[r_ball_ind] <= diag)==10,
                            msg = '\033[91m player r ball displacements: {}\033[00m'.format(f_moment[r_ball_ind]))
            # a2) the player displacements to the hoop
            self.assertTrue(sum(f_moment[r_hoop_ind] > 0) == 10 and sum(f_moment[r_hoop_ind] <= diag)==10,
                            msg = '\033[91m player r hoop displacements: {}\033[00m'.format(f_moment[r_hoop_ind]))

            # b1) the player cos to the ball
            self.assertTrue(sum(f_moment[cos_ball_ind] >= -1) == 10 and sum(f_moment[cos_ball_ind] <= 1)==10,
                            msg = '\033[91m player r ball cos: {}\033[00m'.format(f_moment[cos_ball_ind]))
            # b2) the player cos to the hoop
            self.assertTrue(sum(f_moment[cos_hoop_ind] >= -1) == 10 and sum(f_moment[cos_hoop_ind] <= 1)==10,
                            msg = '\033[91m player r hoop cos: {}\033[00m'.format(f_moment[cos_hoop_ind]))

            # c1) the player sin to the ball
            self.assertTrue(sum(f_moment[sin_ball_ind] >= -1) == 10 and sum(f_moment[sin_ball_ind] <= 1)==10,
                            msg = '\033[91m player r ball sine: {}\033[00m'.format(f_moment[sin_ball_ind]))
            # c2) the player sin to the hoop
            self.assertTrue(sum(f_moment[sin_hoop_ind] >= -1) == 10 and sum(f_moment[sin_hoop_ind] <= 1)==10,
                            msg = '\033[91m player r hoop sine: {}\033[00m'.format(f_moment[sin_hoop_ind]))

            # d1) the player theta to the ball
            self.assertTrue(sum(f_moment[theta_ball_ind] >= 0) == 10 and sum(f_moment[theta_ball_ind] <= np.pi)==10,
                            msg = '\033[91m player r ball theta: {}\033[00m'.format(f_moment[theta_ball_ind]))
            # d2) the player sin to the ball
            self.assertTrue(sum(f_moment[theta_hoop_ind] >= 0) == 10 and sum(f_moment[theta_hoop_ind] <= np.pi)==10,
                            msg = '\033[91m player r hoop theta: {}\033[00m'.format(f_moment[theta_hoop_ind]))

            # e1) cos^2 + sin^2 = 1 ball
            e_tol = 1e-5
            self.assertTrue(sum((f_moment[cos_ball_ind]**2 + f_moment[sin_ball_ind]**2 - 1) < e_tol) == 10,
                msg = '\033[91m sin^2 + cos^2 =1 ball: {}\033[00m'.format(f_moment[cos_ball_ind]**2 + f_moment[sin_ball_ind]**2))
            # e2) hoop
            self.assertTrue(sum((f_moment[cos_hoop_ind]**2 + f_moment[sin_hoop_ind]**2 - 1) < e_tol) == 10,
                msg = '\033[91m sin^2 + cos^2 =1 hoop: {}\033[00m'.format(f_moment[cos_hoop_ind]**2 + f_moment[sin_hoop_ind]**2))


        event_length_th = 30
        for k, e in enumerate(self.event_dfs):
            result, _ = preprocessing.remove_non_eleven(e, event_length_th, verbose=True)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_shotclock(e, event_length_th, verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.chunk_halfcourt(df, event_length_th, verbose=False)
            df = pd.DataFrame({'moments': result})

            result = preprocessing.reorder_teams(df, self.game_ids[k])
            df = pd.DataFrame({'moments': result})

            flattened, _ =  preprocessing.flatten_moments(df)
            df = pd.DataFrame({'moments': flattened})

            result = preprocessing.create_static_features(df)
            [check_static(i[j]) for i in result for j in range(i.shape[0])]