Example #1
0
    def fit_from_w(self,
                   w,
                   attr,
                   n_regions,
                   initial_labels=None,
                   objective_func=ObjectiveFunctionPairwise()):
        """
        Alternative API for :meth:`fit_from_scipy_sparse_matrix`.

        Parameters
        ----------
        w : :class:`libpysal.weights.weights.W`
            W object representing the contiguity relation.
        attr : :class:`numpy.ndarray`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        n_regions : `int`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        initial_labels : :class:`numpy.ndarray` or None, default: None
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        adj = scipy_sparse_matrix_from_w(w)
        self.fit_from_scipy_sparse_matrix(
            adj,
            attr,
            n_regions,
            initial_labels,
            objective_func=objective_func)
Example #2
0
    def fit_from_networkx(self,
                          graph,
                          attr,
                          spatially_extensive_attr,
                          threshold,
                          max_it=10,
                          objective_func=ObjectiveFunctionPairwise()):
        """
        Alternative API for :meth:`fit_from_scipy_sparse_matrix:.

        Parameters
        ----------
        graph : `networkx.Graph`

        attr : str, list or dict
            If the clustering criteria are present in the networkx.Graph
            `graph` as node attributes, then they can be specified as a string
            (for one criterion) or as a list of strings (for multiple
            criteria).
            Alternatively, a dict can be used with each key being a node of the
            networkx.Graph `graph` and each value being the corresponding
            clustering criterion (a scalar (e.g. `float` or `int`) or a
            :class:`numpy.ndarray`).
            If there are no clustering criteria present in the networkx.Graph
            `graph` as node attributes, then a dictionary must be used for this
            argument. Refer to the corresponding argument in
            :meth:`fit_from_dict` for more details about the expected dict.
        spatially_extensive_attr : str, list or dict
            If the spatially extensive attribute is present in the
            networkx.Graph `graph` as node attributes, then they can be
            specified as a string (for one attribute) or as a list of
            strings (for multiple attributes).
            Alternatively, a dict can be used with each key being a node of the
            networkx.Graph `graph` and each value being the corresponding
            spatially extensive attribute (a scalar (e.g. `float` or `int`) or
            a :class:`numpy.ndarray`).
            If there are no spatially extensive attributes present in the
            networkx.Graph `graph` as node attributes, then a dictionary must
            be used for this argument. Refer to the corresponding argument in
            :meth:`fit_from_dict` for more details about the expected dict.
        threshold : numbers.Real or :class:`numpy.ndarray`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        max_it : int, default: 10
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        adj = nx.to_scipy_sparse_matrix(graph)
        attr = array_from_graph_or_dict(graph, attr)
        sp_ext_attr = array_from_graph_or_dict(graph, spatially_extensive_attr)
        self.fit_from_scipy_sparse_matrix(adj,
                                          attr,
                                          sp_ext_attr,
                                          threshold=threshold,
                                          max_it=max_it,
                                          objective_func=objective_func)
Example #3
0
    def fit_from_scipy_sparse_matrix(
            self,
            adj,
            attr,
            n_regions,
            initial_labels=None,
            objective_func=ObjectiveFunctionPairwise()):
        """
        Perform the AZP algorithm as described in [OR1995]_.

        The resulting region labels are assigned to the instance's
        :attr:`labels_` attribute.

        Parameters
        ----------
        adj : :class:`scipy.sparse.csr_matrix`
            Adjacency matrix representing the contiguity relation.
        attr : :class:`numpy.ndarray`
            Array (number of areas x number of attributes) of areas' attributes
            relevant to clustering.
        n_regions : `int`
            Number of desired regions.
        initial_labels : :class:`numpy.ndarray` or None, default: None
            One-dimensional array of labels at the beginning of the algorithm.
            If None, then a random initial clustering will be generated.
        objective_func : :class:`region.objective_function.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            The objective function to use.
        """
        if attr.ndim == 1:
            attr = attr.reshape(adj.shape[0], -1)
        self.allow_move_strategy.attr_all = attr
        self.objective_func = objective_func
        # step 1
        if initial_labels is not None:
            assert_feasible(initial_labels, adj, n_regions)
            initial_labels_gen = separate_components(adj, initial_labels)
        else:
            initial_labels_gen = generate_initial_sol(adj, n_regions)
        labels = -np.ones(adj.shape[0])
        for labels_comp in initial_labels_gen:
            comp_idx = np.where(labels_comp != -1)[0]
            adj_comp = sub_adj_matrix(adj, comp_idx)
            labels_comp = labels_comp[comp_idx]
            attr_comp = attr[comp_idx]
            self.allow_move_strategy.start_new_component(
                labels_comp, attr_comp, self.objective_func, comp_idx)

            labels_comp = self._azp_connected_component(
                adj_comp, labels_comp, attr_comp)
            labels[comp_idx] = labels_comp

        self.n_regions = n_regions
        self.labels_ = labels
Example #4
0
    def fit_from_networkx(self,
                          graph,
                          attr,
                          n_regions,
                          initial_labels=None,
                          objective_func=ObjectiveFunctionPairwise()):
        """
        Alternative API for :meth:`fit_from_scipy_sparse_matrix`.

        Parameters
        ----------
        graph : `networkx.Graph`
            Graph representing the contiguity relation.
        attr : str, list or dict
            If the clustering criteria are present in the networkx.Graph
            `graph` as node attributes, then they can be specified as a string
            (for one criterion) or as a list of strings (for multiple
            criteria).
            Alternatively, a dict can be used with each key being a node of the
            networkx.Graph `graph` and each value being the corresponding
            clustering criterion (a scalar (e.g. `float` or `int`) or a
            :class:`numpy.ndarray`).
            If there are no clustering criteria present in the networkx.Graph
            `graph` as node attributes, then a dictionary must be used for this
            argument. Refer to the corresponding argument in
            :meth:`fit_from_dict` for more details about the expected dict.
        n_regions : `int`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        initial_labels : str or dict or None, default: None
            If str, then the string names the graph's attribute holding the
            information about the initial clustering.
            If dict, then each key is a node and each value is the region the
            key area is assigned to at the beginning of the algorithm.
            If None, then a random initial clustering will be generated.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        adj = nx.to_scipy_sparse_matrix(graph)
        attr = array_from_graph_or_dict(graph, attr)
        if initial_labels is not None:
            initial_labels = array_from_graph_or_dict(graph, initial_labels)
        self.fit_from_scipy_sparse_matrix(
            adj,
            attr,
            n_regions,
            initial_labels,
            objective_func=objective_func)
Example #5
0
    def fit_from_geodataframe(self,
                              gdf,
                              attr,
                              spatially_extensive_attr,
                              threshold,
                              max_it=10,
                              objective_func=ObjectiveFunctionPairwise(),
                              contiguity="rook"):
        """
        Alternative API for :meth:`fit_from_scipy_sparse_matrix:.

        Parameters
        ----------
        gdf : :class:`geopandas.GeoDataFrame`

        attr : str or list
            The clustering criteria (columns of the GeoDataFrame `gdf`) are
            specified as string (for one column) or list of strings (for
            multiple columns).
        spatially_extensive_attr : str or list
            The name (`str`) or names (`list` of strings) of column(s) in `gdf`
            containing the spatially extensive attributes.
        threshold : numbers.Real or :class:`numpy.ndarray`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        max_it : int, default: 10
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        contiguity : {"rook", "queen"}, default: "rook"
            Defines the contiguity relationship between areas. Possible
            contiguity definitions are:

            * "rook" - Rook contiguity.
            * "queen" - Queen contiguity.
        """
        w = w_from_gdf(gdf, contiguity)
        attr = array_from_df_col(gdf, attr)
        spat_ext_attr = array_from_df_col(gdf, spatially_extensive_attr)

        self.fit_from_w(w,
                        attr,
                        spat_ext_attr,
                        threshold=threshold,
                        max_it=max_it,
                        objective_func=objective_func)
Example #6
0
    def fit_from_dict(self,
                      neighbor_dict,
                      attr,
                      n_regions,
                      initial_labels=None,
                      objective_func=ObjectiveFunctionPairwise()):
        """
        Alternative API for :meth:`fit_from_scipy_sparse_matrix`.

        Parameters
        ----------
        neighbor_dict : `dict`
            Each key is an area and each value is an iterable of the key area's
            neighbors.
        attr : `dict`
            Each key is an area and each value is the corresponding
            clustering-relevant attribute.
        n_regions : `int`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        initial_labels : `dict` or None, default: None
            Each key represents an area. Each value represents the region, the
            corresponding area is assigned to at the beginning of the
            algorithm.
            If None, then a random initial clustering will be generated.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        sorted_areas = sorted(neighbor_dict)

        adj = scipy_sparse_matrix_from_dict(neighbor_dict)
        attr_arr = array_from_dict_values(attr, sorted_areas)

        if initial_labels is not None:
            initial_labels = array_from_dict_values(
                initial_labels, sorted_areas, flat_output=True, dtype=np.int32)
        self.fit_from_scipy_sparse_matrix(
            adj,
            attr_arr,
            n_regions,
            initial_labels,
            objective_func=objective_func)
Example #7
0
 def fit_from_geodataframe(self,
                           gdf,
                           attr,
                           n_regions,
                           contiguity="rook",
                           initial_labels=None,
                           cooling_factor=0.85,
                           objective_func=ObjectiveFunctionPairwise()):
     """
     Parameters
     ----------
     gdf : :class:`geopandas.GeoDataFrame`
         Refer to the corresponding argument in
         :meth:`AZP.fit_from_geodataframe`.
     attr : `str` or `list`
         Refer to the corresponding argument in
         :meth:`AZP.fit_from_geodataframe`.
     n_regions : `int`
         Refer to the corresponding argument in
         :meth:`AZP.fit_from_geodataframe`.
     contiguity : `str`
         Refer to the corresponding argument in
         :meth:`AZP.fit_from_geodataframe`.
     initial_labels : :class:`numpy.ndarray` or None, default: None
         Refer to the corresponding argument in
         :meth:`AZP.fit_from_geodataframe`.
     cooling_factor : float, default: 0.85
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     """
     w = w_from_gdf(gdf, contiguity)
     attr = array_from_df_col(gdf, attr)
     self.fit_from_w(
         w,
         attr,
         n_regions,
         initial_labels,
         cooling_factor=cooling_factor,
         objective_func=objective_func)
Example #8
0
 def fit_from_networkx(self,
                       graph,
                       attr,
                       n_regions,
                       initial_labels=None,
                       cooling_factor=0.85,
                       objective_func=ObjectiveFunctionPairwise()):
     """
     Parameters
     ----------
     graph : `networkx.Graph`
         Refer to the corresponding argument in
         :meth:`AZP.fit_from_networkx`.
     attr : str, list or dict
         Refer to the corresponding argument in
         :meth:`AZP.fit_from_networkx`.
     n_regions : `int`
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     initial_labels : str or dict or None, default: None
         Refer to the corresponding argument in
         :meth:`AZP.fit_from_networkx`.
     cooling_factor : float, default: 0.85
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     """
     adj = nx.to_scipy_sparse_matrix(graph)
     attr = array_from_graph_or_dict(graph, attr)
     if initial_labels is not None:
         initial_labels = array_from_graph_or_dict(graph, initial_labels)
     self.fit_from_scipy_sparse_matrix(
         adj,
         attr,
         n_regions,
         initial_labels,
         cooling_factor=cooling_factor,
         objective_func=objective_func)
Example #9
0
    def fit_from_dict(self,
                      neighbor_dict,
                      attr,
                      n_regions,
                      initial_labels=None,
                      cooling_factor=0.85,
                      objective_func=ObjectiveFunctionPairwise()):
        """
        Parameters
        ----------
        neighbor_dict : `dict`
            Refer to the corresponding argument in :meth:`AZP.fit_from_dict`.
        attr : `dict`
            Refer to the corresponding argument in :meth:`AZP.fit_from_dict`.
        n_regions : `int`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        initial_labels : `dict` or None, default: None
            Refer to the corresponding argument in :meth:`AZP.fit_from_dict`.
        cooling_factor : float, default: 0.85
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        sorted_areas = sorted(neighbor_dict)
        adj = scipy_sparse_matrix_from_dict(neighbor_dict)
        attr_arr = array_from_dict_values(attr, sorted_areas)

        if initial_labels is not None:
            initial_labels = array_from_dict_values(
                initial_labels, sorted_areas, flat_output=True, dtype=np.int32)
        self.fit_from_scipy_sparse_matrix(
            adj,
            attr_arr,
            n_regions,
            initial_labels=initial_labels,
            cooling_factor=cooling_factor,
            objective_func=objective_func)
Example #10
0
    def fit_from_w(self,
                   w,
                   attr,
                   spatially_extensive_attr,
                   threshold,
                   max_it=10,
                   objective_func=ObjectiveFunctionPairwise()):
        """
        Alternative API for :meth:`fit_from_scipy_sparse_matrix:.

        Parameters
        ----------
        w : :class:`libpysal.weights.weights.W`
            W object representing the contiguity relation.
        attr : :class:`numpy.ndarray`
            Each element specifies an area's attribute which is used for
            calculating the objective function.
        spatially_extensive_attr : :class:`numpy.ndarray`
            Each element specifies an area's spatially extensive attribute
            which is used to ensure that the sum of spatially extensive
            attributes in each region adds up to a threshold defined by the
            `threshold` argument.
        threshold : numbers.Real or :class:`numpy.ndarray`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        max_it : int, default: 10
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        adj = scipy_sparse_matrix_from_w(w)
        self.fit_from_scipy_sparse_matrix(adj,
                                          attr,
                                          spatially_extensive_attr,
                                          threshold,
                                          max_it=max_it,
                                          objective_func=objective_func)
Example #11
0
    def fit_from_geodataframe(self,
                              gdf,
                              attr,
                              n_regions,
                              contiguity="rook",
                              initial_labels=None,
                              objective_func=ObjectiveFunctionPairwise()):
        """
        Alternative API for :meth:`fit_from_scipy_sparse_matrix`.

        Parameters
        ----------
        gdf : :class:`geopandas.GeoDataFrame`

        attr : `str` or `list`
            The clustering-relevant attributes (columns of the GeoDataFrame
            `gdf`) are specified as string (for one column) or list of strings
            (for multiple columns).
        n_regions : `int`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        contiguity : {"rook", "queen"}, default: "rook"
            Defines the contiguity relationship between areas. Possible
            contiguity definitions are:

            * "rook" - Rook contiguity.
            * "queen" - Queen contiguity.

        initial_labels : :class:`numpy.ndarray` or None, default: None
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        w = w_from_gdf(gdf, contiguity)
        attr = array_from_df_col(gdf, attr)
        self.fit_from_w(
            w, attr, n_regions, initial_labels, objective_func=objective_func)
Example #12
0
 def fit_from_w(self,
                w,
                attr,
                n_regions,
                initial_labels=None,
                cooling_factor=0.85,
                objective_func=ObjectiveFunctionPairwise()):
     """
     Parameters
     ----------
     w : :class:`libpysal.weights.weights.W`
         Refer to the corresponding argument in :meth:`AZP.fit_from_w`.
     attr : :class:`numpy.ndarray`
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     n_regions : `int`
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     initial_labels : :class:`numpy.ndarray` or None, default: None
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     cooling_factor : float, default: 0.85
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
         Refer to the corresponding argument in
         :meth:`fit_from_scipy_sparse_matrix`.
     """
     adj = scipy_sparse_matrix_from_w(w)
     self.fit_from_scipy_sparse_matrix(
         adj,
         attr,
         n_regions,
         initial_labels,
         cooling_factor=cooling_factor,
         objective_func=objective_func)
Example #13
0
    def fit_from_scipy_sparse_matrix(
        self,
        adj,
        attr,
        spatially_extensive_attr,
        threshold,
        max_it=10,
        objective_func=ObjectiveFunctionPairwise()):
        """
        Solve the max-p-regions problem in a heuristic way (see [DAR2012]_).

        The resulting region labels are assigned to the instance's
        :attr:`labels_` attribute.

        Parameters
        ----------
        adj : :class:`scipy.sparse.csr_matrix`
            Adjacency matrix representing the areas' contiguity relation.
        attr : :class:`numpy.ndarray`
            Array (number of areas x number of attributes) of areas' attributes
            relevant to clustering.
        spatially_extensive_attr : :class:`numpy.ndarray`
            Array (number of areas x number of attributes) of areas' attributes
            relevant to ensuring the threshold condition.
        threshold : numbers.Real or :class:`numpy.ndarray`
            The lower bound for a region's sum of spatially extensive
            attributes. The argument's type is numbers.Real if there is only
            one spatially extensive attribute per area, otherwise it is a
            one-dimensional array with as many entries as there are spatially
            extensive attributes per area.
        max_it : int, default: 10
            The maximum number of partitions produced in the algorithm's
            construction phase.
        objective_func : :class:`region.objective_function.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            The objective function to use.
        """
        print("f_f_SCIPY got:\n",
              attr,
              "\n",
              spatially_extensive_attr,
              "\n",
              threshold,
              sep="")
        weights = ps_api.WSP(adj).to_W()
        areas_dict = weights.neighbors
        self.metric = objective_func.metric

        best_partition = None
        best_obj_value = float("inf")
        feasible_partitions = []
        partitions_before_enclaves_assignment = []
        max_p = 0  # maximum number of regions

        # construction phase
        # print("constructing")
        for _ in range(max_it):
            # print(" ", _)
            partition, enclaves = self.grow_regions(adj, attr,
                                                    spatially_extensive_attr,
                                                    threshold)
            n_regions = len(partition)
            if n_regions > max_p:
                partitions_before_enclaves_assignment = [(partition, enclaves)]
                max_p = n_regions
            elif n_regions == max_p:
                partitions_before_enclaves_assignment.append(
                    (partition, enclaves))

        # print("\n" + "assigning enclaves")
        for partition, enclaves in partitions_before_enclaves_assignment:
            # print("  cleaning up in partition", partition)
            feasible_partitions.append(
                self.assign_enclaves(partition, enclaves, areas_dict, attr))

        for partition in feasible_partitions:
            print(partition, "\n")

        # local search phase
        if self.local_search is None:
            self.local_search = AZP()
        self.local_search.allow_move_strategy = AllowMoveAZPMaxPRegions(
            spatially_extensive_attr, threshold,
            self.local_search.allow_move_strategy)
        for partition in feasible_partitions:
            self.local_search.fit_from_scipy_sparse_matrix(
                adj,
                attr,
                max_p,
                initial_labels=array_from_region_list(partition),
                objective_func=objective_func)
            partition = self.local_search.labels_
            # print("optimized partition", partition)
            obj_value = objective_func(partition, attr)
            if obj_value < best_obj_value:
                best_obj_value = obj_value
                best_partition = partition
        self.labels_ = best_partition
Example #14
0
    def fit_from_dict(self,
                      neighbors_dict,
                      attr,
                      spatially_extensive_attr,
                      threshold,
                      max_it=10,
                      objective_func=ObjectiveFunctionPairwise()):
        """
        Solve the max-p-regions problem in a heuristic way (see [DAR2012]_).

        The resulting region labels are assigned to the instance's
        :attr:`labels_` attribute.

        Parameters
        ----------
        neighbors_dict : dict
            Each key represents an area and each value is an iterable of
            neighbors of this area.
        attr : dict
            A dict with the same keys as `neighbors_dict` and values
            representing the attributes for calculating h**o-/heterogeneity. A
            value can be scalar (e.g. `float` or `int`) or a
            :class:`numpy.ndarray`.
        spatially_extensive_attr : dict
            A dict with the same keys as `neighbors_dict` and values
            representing the spatially extensive attribute (scalar or iterable
            of scalars). In the max-p-regions problem each region's sum of
            spatially extensive attributes must be greater than a specified
            threshold. In case of iterables of scalars as dict-values all
            elements of the iterable have to fulfill the condition.
        threshold : numbers.Real or :class:`numpy.ndarray`
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        max_it : int, default: 10
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        if not isinstance(neighbors_dict, dict):
            raise ValueError("The neighbors_dict argument must be dict.")

        not_same_dict_keys_msg = "The {} argument has to be of type dict " \
                                 "with the same keys as neighbors_dict."

        if not isinstance(attr, dict) or attr.keys() != neighbors_dict.keys():
            raise ValueError(not_same_dict_keys_msg.format("attr"))

        if not isinstance(spatially_extensive_attr, dict) or \
                spatially_extensive_attr.keys() != neighbors_dict.keys():
            raise ValueError(
                not_same_dict_keys_msg.format(spatially_extensive_attr))
        adj = scipy_sparse_matrix_from_dict(neighbors_dict)
        attr_arr = array_from_dict_values(attr)
        spat_ext_attr_arr = array_from_dict_values(spatially_extensive_attr)
        self.fit_from_scipy_sparse_matrix(adj,
                                          attr_arr,
                                          spat_ext_attr_arr,
                                          threshold=threshold,
                                          max_it=max_it,
                                          objective_func=objective_func)
Example #15
0
    def fit_from_scipy_sparse_matrix(
            self,
            adj,
            attr,
            n_regions,
            initial_labels=None,
            cooling_factor=0.85,
            objective_func=ObjectiveFunctionPairwise()):
        """
        Parameters
        ----------
        adj : :class:`scipy.sparse.csr_matrix`
            Refer to the corresponding argument in
            :meth:`AZP.fit_from_scipy_sparse_matrix`.
        attr : :class:`numpy.ndarray`
            Refer to the corresponding argument in
            :meth:`AZP.fit_from_scipy_sparse_matrix`.
        n_regions : `int`
            Refer to the corresponding argument in
            :meth:`AZP.fit_from_scipy_sparse_matrix`.
        initial_labels : :class:`numpy.ndarray` or None, default: None
            Refer to the corresponding argument in
            :meth:`AZP.fit_from_scipy_sparse_matrix`.
        cooling_factor : float, default: 0.85
            Float :math:`\\in (0, 1)` specifying the cooling factor for the
            simulated annealing.
        objective_func : :class:`region.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            Refer to the corresponding argument in
            :meth:`fit_from_scipy_sparse_matrix`.
        """
        if not (0 < cooling_factor < 1):
            raise ValueError("The cooling_factor argument must be greater "
                             "than 0 and less than 1")
        if attr.ndim == 1:
            attr = attr.reshape(adj.shape[0], -1)
        self.allow_move_strategy = AllowMoveAZPSimulatedAnnealing(
            init_temperature=self.init_temperature,
            sa_moves_term=self.sa_moves_term)
        self.allow_move_strategy.register_sa_moves_term(self.sa_moves_alert)
        self.allow_move_strategy.register_move_made(self.move_made_alert)

        self.azp = AZP(
            allow_move_strategy=self.allow_move_strategy,
            random_state=self.random_state)
        # step a
        t = self.init_temperature
        nonmoving_steps = 0
        # step d: repeat step b and c
        while nonmoving_steps < self.nonmoving_steps_before_stop:
            it = 0
            self.sa_moves_term_reached = False
            self.allow_move_strategy.reset()
            # step b
            while it < self.maxit and not self.sa_moves_term_reached:
                it += 1
                old_sol = initial_labels
                self.azp.fit_from_scipy_sparse_matrix(
                    adj, attr, n_regions, initial_labels, objective_func)
                initial_labels = self.azp.labels_

                if old_sol is not None:

                    if (old_sol == initial_labels).all():
                        break
            # added termination condition (not in Openshaw & Rao (1995))
            if self.visited.count(tuple(initial_labels)) \
                    >= self.reps_before_termination:
                break
            self.visited.append(tuple(initial_labels))
            # step c
            t *= cooling_factor
            self.allow_move_strategy.update_temperature(t)

            if self.move_made:
                self.move_made = False
            else:
                nonmoving_steps += 1
        self.labels_ = initial_labels