def extract_profile(graph: FullGraph, user_id: str) -> Dict: """ Extracts the user profile (the items that the user rated, or in general the nodes with a link to the user). Returns a dictionary containing the successor nodes as keys and the weights in the graph for the edges between the user node and his successors as values EXAMPLE:: graph: i1 <---0.2--- u1 ---0.4---> i2 > print(extract_profile('u1')) > {'i1': 0.2, 'i2': 0.4} Args: graph (FullGraph): graph from which the profile of the user will be extracted user_id (str): id for the user for which the profile will be extracted Returns: profile (dict): dictionary with item successor nodes to the user as keys and weights of the edge connecting them in the graph as values """ succ = graph.get_successors(UserNode(user_id)) profile = { a: graph.get_link_data(UserNode(user_id), a)['weight'] for a in succ } return profile # {t: w for (f, t, w) in adj}
def add_user_node(self, node: object): """ Adds a 'user' node to the graph. If the node is not-existent then it is created and then added to the graph. Args: node (object): node that needs to be added to the graph as a from node """ self.__graph.add_node(UserNode(node))
def test_filter_result(self): result_page_rank = { ItemNode("i1"): 0.8, ItemNode("i2"): 0.7, UserNode('u1'): 0.2, PropertyNode("p1"): 0.1 } result = self.alg.filter_result(result_page_rank, ['i1']) expected = {ItemNode("i1"): 0.8} self.assertEqual(expected, result) result = self.alg.filter_result(result_page_rank, ['u1', 'p1']) expected = {UserNode('u1'): 0.2, PropertyNode("p1"): 0.1} self.assertEqual(expected, result) # filter with non existent nodes, result will be empty result = self.alg.filter_result(result_page_rank, ['not exists', 'i20']) expected = {} self.assertEqual(expected, result)
def test_extract_profile(self): result = self.alg.extract_profile(self.graph, "A000") expected = {'tt0112453': -0.2, 'tt0113041': 0.6, 'tt0114576': 1.0} self.assertEqual(expected, result) # Also if you wrap items in its corresponding type will work expected_wrapped = { ItemNode('tt0112453'): -0.2, ItemNode('tt0113041'): 0.6, ItemNode('tt0114576'): 1.0 } self.assertEqual(expected_wrapped, result) # This will fail because they are not users expected_wrapped_fake = { UserNode('tt0112453'): -0.2, UserNode('tt0113041'): 0.6, UserNode('tt0114576'): 1.0 } self.assertNotEqual(expected_wrapped_fake, result)
def add_user_node(self, node: Union[object, List[object]]): """ Adds a 'user' node to the graph. If the node is not-existent then it is created and then added to the graph. Args: node (object): node that needs to be added to the graph as a from node """ if not isinstance(node, list): node = [node] for n in node: self._graph.add_node(UserNode(n))
def add_user_node(self, node: Union[object, List[object]]): """ Adds a 'user' node to the graph. If a list is passed, then every element of the list will be added as a 'user' node Args: node: node(s) that needs to be added to the graph as 'user' node(s) """ if not isinstance(node, list): node = [node] for n in node: self._graph.add_node(UserNode(n))
def test_clean_rank(self): rank = { UserNode("A000"): 0.5, ItemNode("tt0114576"): 0.5, UserNode("A001"): 0.5, ItemNode("tt0113497"): 0.5, ItemNode("tt0112453"): 0.5, PropertyNode("Nolan"): 0.5 } # remove from rank all nodes except Item nodes result = self.alg.clean_result(self.graph, rank, user_id="A000") expected = {"tt0113497": 0.5} self.assertEqual(expected, result) # remove from rank all nodes except Item nodes and User nodes result = self.alg.clean_result(self.graph, rank, user_id="A000", remove_users=False) expected = {"tt0113497": 0.5, "A001": 0.5, "A000": 0.5} self.assertEqual(expected, result) # remove from rank all nodes except Item nodes and keep item rated by the user result = self.alg.clean_result(self.graph, rank, user_id="A000", remove_profile=False) expected = {'tt0112453': 0.5, 'tt0113497': 0.5, 'tt0114576': 0.5} self.assertEqual(expected, result) # remove from rank all nodes except Item nodes and property nodes result = self.alg.clean_result(self.graph, rank, user_id="A000", remove_properties=False) expected = {'tt0113497': 0.5, 'Nolan': 0.5} self.assertEqual(expected, result)
def process_feature_selection_on_fullgraph( self, graph: FullGraph, user_target_nodes: List[object], item_target_nodes: List[object]) -> FullGraph: """ Given a FullGraph, this method performs feature selection on said graph. It also allows to define a custom list of user and item nodes which properties will be considered during the feature selection process (instead of using the whole set of user and item nodes). Args: graph (FullGraph): original graph on which feature selection will be performed user_target_nodes (list): list of user nodes (or values of said nodes) to consider in the feature selection process item_target_nodes (list): list of item nodes (or values of said nodes) to consider in the feature selection process Returns: Copy of the original graph from which the less important Property nodes (the ones having edges with less important property labels) will be removed """ if any(not graph.is_user_node(node) for node in user_target_nodes): raise FeatureSelectionException( 'All nodes in user_target_nodes list must be user nodes') if any(not graph.is_item_node(node) for node in item_target_nodes): raise FeatureSelectionException( 'All nodes in item_target_nodes list must be item nodes') if any(not isinstance(node, UserNode) for node in user_target_nodes): user_target_nodes = [ UserNode(node) if not isinstance(node, UserNode) else node for node in user_target_nodes ] if any(not isinstance(node, ItemNode) for node in item_target_nodes): item_target_nodes = [ ItemNode(node) if not isinstance(node, ItemNode) else node for node in item_target_nodes ] properties_to_keep = list() user_fs_failed = False item_fs_failed = False recsys_logger.info("Performing Feature Selection on users") try: properties_to_keep.extend( self.__feature_selection_algorithm.perform( graph, user_target_nodes)) except FeatureSelectionException as e: recsys_logger.warning( str(e) + "! Users original properties will be kept") user_fs_failed = True recsys_logger.info("Performing Feature Selection on items") try: properties_to_keep.extend( self.__feature_selection_algorithm.perform( graph, item_target_nodes)) except FeatureSelectionException as e: recsys_logger.warning( str(e) + "! Items original properties will be kept") item_fs_failed = True # in case user feature selection or item feature selection failed # if both failed the original graph is returned # if only one of them failed, the original properties (either for items or users) are retrieved if user_fs_failed and item_fs_failed: recsys_logger.warning( "Since items and users original properties will be kept, " "the original graph will be returned") return graph elif user_fs_failed and not item_fs_failed: properties_to_keep.extend( self._get_property_labels_info(graph, graph.user_nodes)) elif not user_fs_failed and item_fs_failed: properties_to_keep.extend( self._get_property_labels_info(graph, graph.item_nodes)) return self.__delete_property_nodes(graph, properties_to_keep)