def test_minimum_weight_full_matching_requires_complete_input(self): G = nx.Graph() G.add_nodes_from([1, 2, 3, 4], bipartite=0) G.add_nodes_from(['a', 'b', 'c'], bipartite=1) G.add_edges_from([(1, 'a'), (1, 'b'), (2, 'b'), (2, 'c'), (3, 'c'), (4, 'a')]) minimum_weight_full_matching(G)
def test_minimum_weight_full_matching_with_no_full_matching(self): B = nx.Graph() B.add_nodes_from([1, 2, 3], bipartite=0) B.add_nodes_from([4, 5, 6], bipartite=1) B.add_edge(1, 4, weight=100) B.add_edge(2, 4, weight=100) B.add_edge(3, 4, weight=50) B.add_edge(3, 5, weight=50) B.add_edge(3, 6, weight=50) with pytest.raises(ValueError): minimum_weight_full_matching(B)
def dispatch(self, dispatch_observ): """ Compute the assignment between drivers and passengers at each time step :param dispatch_observ: a list of dict, the key in the dict includes: order_id, int driver_id, int order_driver_distance, float order_start_location, a list as [lng, lat], float order_finish_location, a list as [lng, lat], float driver_location, a list as [lng, lat], float timestamp, int order_finish_timestamp, int day_of_week, int reward_units, float pick_up_eta, float :return: a list of dict, the key in the dict includes: order_id and driver_id, the pair indicating the assignment """ """ dispatch_observ.sort(key=lambda od_info: od_info['reward_units'], reverse=True) assigned_order = set() assigned_driver = set() dispatch_action = [] for od in dispatch_observ: # make sure each order is assigned to one driver, and each driver is assigned with one order if (od["order_id"] in assigned_order) or (od["driver_id"] in assigned_driver): continue assigned_order.add(od["order_id"]) assigned_driver.add(od["driver_id"]) dispatch_action.append(dict(order_id=od["order_id"], driver_id=od["driver_id"])) return dispatch_action """ id_order = list({}.fromkeys(od['order_id'] for od in dispatch_observ).keys()) id_driver = list({}.fromkeys(od['driver_id'] for od in dispatch_observ).keys()) order_id = dict((order, idx) for idx, order in enumerate(id_order)) driver_id = dict((driver, idx) for idx, driver in enumerate(id_driver)) N = len(order_id) M = len(driver_id) import networkx as nx G = nx.complete_bipartite_graph(N, M) for od in dispatch_observ: order = order_id[od['order_id']] driver = N + driver_id[od['driver_id']] G.edges[order, driver]['weight'] = -od['reward_units'] from networkx.algorithms.bipartite.matching import minimum_weight_full_matching match = minimum_weight_full_matching(G) dispatch_action = [] for idx, order in enumerate(id_order): dispatch_action.append({ 'driver_id': id_driver[match[idx] - N], 'order_id': order }) return dispatch_action
def test_minimum_weight_full_matching_different_weight_key(self): G = nx.complete_bipartite_graph(2, 2) G.add_edge(0, 2, mass=2) G.add_edge(0, 3, mass=0.2) G.add_edge(1, 2, mass=1) G.add_edge(1, 3, mass=2) matching = minimum_weight_full_matching(G, weight="mass") assert matching == {0: 3, 1: 2, 2: 1, 3: 0}
def test_minimum_weight_full_matching_negative_weights(self): G = nx.complete_bipartite_graph(2, 2) G.add_edge(0, 2, weight=-2) G.add_edge(0, 3, weight=0.2) G.add_edge(1, 2, weight=-2) G.add_edge(1, 3, weight=0.3) matching = minimum_weight_full_matching(G) assert matching == {0: 3, 1: 2, 2: 1, 3: 0}
def test_minimum_weight_full_matching_incomplete_graph(self): B = nx.Graph() B.add_nodes_from([1, 2], bipartite=0) B.add_nodes_from([3, 4], bipartite=1) B.add_edge(1, 4, weight=100) B.add_edge(2, 3, weight=100) B.add_edge(2, 4, weight=50) matching = minimum_weight_full_matching(B) assert matching == {1: 4, 2: 3, 4: 1, 3: 2}
def score(self, prediction, metric='f1', average='macro'): """ :param prediction: The prediction of your model. Dict of dict like {tag: {lemma: word}}. :param metric: Metric for calculating per-slot-pair score. :param average: Type of average. :returns: The overall score. """ self._check_dict_dict(prediction, lambda s: isinstance(s, str), 'prediction') if metric not in ['f1', 'precision', 'recall']: raise ValueError( "'metric' must be 'precision', 'recall' or 'f1', got '{}'.". format(metric)) if average not in ['micro', 'macro']: raise ValueError( "'average' must be 'micro' or 'macro', got '{}'.".format( average)) graph = nx.Graph() prd_nodes = frozenset('prd_' + tag for tag in prediction.keys()) ref_nodes = frozenset('ref_' + tag for tag in self.reference.keys()) graph.add_nodes_from(prd_nodes) graph.add_nodes_from(ref_nodes) for prd_tag, prd_dict in prediction.items(): for ref_tag, ref_dict in self.reference.items(): true_pos = 0 for lemma, prd_word in prd_dict.items(): ref_set = ref_dict.get(lemma) if ref_set is not None and prd_word in ref_set: true_pos += 1 if average == 'micro': tag_score = true_pos else: tag_score = self._get_metric(true_pos, len(prd_dict), len(ref_dict), metric) graph.add_edge('prd_' + prd_tag, 'ref_' + ref_tag, weight=-tag_score) matches = minimum_weight_full_matching(graph, prd_nodes) match_score = 0 for prd_node, ref_node in matches.items(): if prd_node in prd_nodes: match_score -= graph[prd_node][ref_node]['weight'] if average == 'micro': total_prd = sum(len(prd_dict) for prd_dict in prediction.values()) total_ref = sum(len(ref_dict) for ref_dict in reference.values()) final_score = self._get_metric(match_score, total_prd, total_ref, metric) return final_score * len(self.reference) / max( len(self.reference), len(prediction)) else: return match_score / max(len(self.reference), len(prediction))
def test_minimum_weight_full_matching_square(self): G = nx.complete_bipartite_graph(3, 3) G.add_edge(0, 3, weight=400) G.add_edge(0, 4, weight=150) G.add_edge(0, 5, weight=400) G.add_edge(1, 3, weight=400) G.add_edge(1, 4, weight=450) G.add_edge(1, 5, weight=600) G.add_edge(2, 3, weight=300) G.add_edge(2, 4, weight=225) G.add_edge(2, 5, weight=300) matching = minimum_weight_full_matching(G) assert matching == {0: 4, 1: 3, 2: 5, 4: 0, 3: 1, 5: 2}
def test_minimum_weight_full_matching_smaller_right(self): G = nx.complete_bipartite_graph(4, 3) G.add_edge(0, 4, weight=400) G.add_edge(0, 5, weight=400) G.add_edge(0, 6, weight=300) G.add_edge(1, 4, weight=150) G.add_edge(1, 5, weight=450) G.add_edge(1, 6, weight=225) G.add_edge(2, 4, weight=400) G.add_edge(2, 5, weight=600) G.add_edge(2, 6, weight=290) G.add_edge(3, 4, weight=1) G.add_edge(3, 5, weight=2) G.add_edge(3, 6, weight=3) matching = minimum_weight_full_matching(G) assert matching == {1: 4, 2: 6, 3: 5, 4: 1, 5: 3, 6: 2}
def test_minimum_weight_full_matching_smaller_top_nodes_right(self): G = nx.complete_bipartite_graph(3, 4) G.add_edge(0, 3, weight=400) G.add_edge(0, 4, weight=150) G.add_edge(0, 5, weight=400) G.add_edge(0, 6, weight=1) G.add_edge(1, 3, weight=400) G.add_edge(1, 4, weight=450) G.add_edge(1, 5, weight=600) G.add_edge(1, 6, weight=2) G.add_edge(2, 3, weight=300) G.add_edge(2, 4, weight=225) G.add_edge(2, 5, weight=290) G.add_edge(2, 6, weight=3) matching = minimum_weight_full_matching(G, top_nodes=[3, 4, 5, 6]) assert matching == {0: 4, 1: 6, 2: 5, 4: 0, 5: 2, 6: 1}
def test_minimum_weight_full_matching_smaller_left(self): G = nx.complete_bipartite_graph(3, 4) G.add_edge(0, 3, weight=400) G.add_edge(0, 4, weight=150) G.add_edge(0, 5, weight=400) G.add_edge(0, 6, weight=1) G.add_edge(1, 3, weight=400) G.add_edge(1, 4, weight=450) G.add_edge(1, 5, weight=600) G.add_edge(1, 6, weight=2) G.add_edge(2, 3, weight=300) G.add_edge(2, 4, weight=225) G.add_edge(2, 5, weight=290) G.add_edge(2, 6, weight=3) matching = minimum_weight_full_matching(G) assert_equal(matching, {0: 4, 1: 6, 2: 5, 4: 0, 5: 2, 6: 1})
print("Assigning edge weights...") if args.normalize_weight: weight_param_name = 'norm_'+args.weight_param else: weight_param_name = args.weight_param set1_vs_set2_weights = df_to_dict(set1_vs_set2_weights, weight_param_name) set2_vs_set1_weights = df_to_dict(set2_vs_set1_weights, weight_param_name) for edge in bg.edges: q = set1_proteins[edge[0]] s = set2_proteins[edge[1]] bidirectional_weight = calculate_biderectional_weight(set1_vs_set2_weights, set2_vs_set1_weights, q, s) bg.edges[edge]['weight'] = bidirectional_weight # find max weight matching print("Finding max weight matching...") mw = minimum_weight_full_matching(bg) # print out matches print("Writing out results...") with open(args.out_tsv, 'w') as fo: print("%s\t%s\t%s weight" %(args.set1_name, args.set2_name, args.weight_param), file=fo) for match in mw: source, target = match, mw[match] if target < source: # each match appears in both directions in the output dict continue match_weight = -1 * bg[source][target]['weight'] if match_weight > 0: q_name = set1_proteins[source] s_name = set2_proteins[target] print("%s\t%s\t%s" %(q_name, s_name, match_weight), file=fo)