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}
예제 #2
0
    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))
예제 #3
0
    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)
예제 #4
0
    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))
예제 #6
0
    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))
예제 #7
0
    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)