class DistanceBand(W): """ Spatial weights based on distance band. Parameters ---------- data : array (n,k) or KDTree where KDtree.data is array (n,k) n observations on k characteristics used to measure distances between the n objects threshold : float distance band p : float Minkowski p-norm distance metric parameter: 1<=p<=infinity 2: Euclidean distance 1: Manhattan distance binary : boolean If true w_{ij}=1 if d_{i,j}<=threshold, otherwise w_{i,j}=0 If false wij=dij^{alpha} alpha : float distance decay parameter for weight (default -1.0) if alpha is positive the weights will not decline with distance. If binary is True, alpha is ignored ids : list values to use for keys of the neighbors and weights dicts Attributes ---------- weights : dict of neighbor weights keyed by observation id neighbors : dict of neighbors keyed by observation id Examples -------- >>> points=[(10, 10), (20, 10), (40, 10), (15, 20), (30, 20), (30, 30)] >>> wcheck = pysal.W({0: [1, 3], 1: [0, 3], 2: [], 3: [0, 1], 4: [5], 5: [4]}) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w=DistanceBand(points,threshold=11.2) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> pysal.weights.util.neighbor_equality(w, wcheck) True >>> w=DistanceBand(points,threshold=14.2) >>> wcheck = pysal.W({0: [1, 3], 1: [0, 3, 4], 2: [4], 3: [1, 0], 4: [5, 2, 1], 5: [4]}) >>> pysal.weights.util.neighbor_equality(w, wcheck) True inverse distance weights >>> w=DistanceBand(points,threshold=11.2,binary=False) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.10000000000000001, 0.089442719099991588] >>> w.neighbors[0] [1, 3] >>> gravity weights >>> w=DistanceBand(points,threshold=11.2,binary=False,alpha=-2.) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.01, 0.0079999999999999984] Notes ----- This was initially implemented running scipy 0.8.0dev (in epd 6.1). earlier versions of scipy (0.7.0) have a logic bug in scipy/sparse/dok.py so serge changed line 221 of that file on sal-dev to fix the logic bug. """ def __init__(self, data, threshold, p=2, alpha=-1.0, binary=True, ids=None): """Casting to floats is a work around for a bug in scipy.spatial. See detail in pysal issue #126. """ if isKDTree(data): self.kd = data self.data = self.kd.data else: try: data = np.asarray(data) if data.dtype.kind != 'f': data = data.astype(float) self.data = data self.kd = KDTree(self.data) except: raise ValueError("Could not make array from data") self.p = p self.threshold = threshold self.binary = binary self.alpha = alpha self._band() neighbors, weights = self._distance_to_W(ids) W.__init__(self, neighbors, weights, ids) def _band(self): """Find all pairs within threshold. """ self.dmat = self.kd.sparse_distance_matrix(self.kd, max_distance=self.threshold) def _distance_to_W(self, ids=None): if ids: ids = np.array(ids) else: ids = np.arange(self.dmat.shape[0]) neighbors = dict([(i, []) for i in ids]) weights = dict([(i, []) for i in ids]) if self.binary: for key, weight in self.dmat.items(): i, j = key if i != j: if j not in neighbors[i]: weights[i].append(1) neighbors[i].append(j) if i not in neighbors[j]: weights[j].append(1) neighbors[j].append(i) else: for key, weight in self.dmat.items(): i, j = key if i != j: if j not in neighbors[i]: weights[i].append(weight**self.alpha) neighbors[i].append(j) if i not in neighbors[j]: weights[j].append(weight**self.alpha) neighbors[j].append(i) return neighbors, weights
class DistanceBand(W): """ Spatial weights based on distance band. Parameters ---------- data : array (n,k) or KDTree where KDtree.data is array (n,k) n observations on k characteristics used to measure distances between the n objects threshold : float distance band p : float Minkowski p-norm distance metric parameter: 1<=p<=infinity 2: Euclidean distance 1: Manhattan distance binary : boolean If true w_{ij}=1 if d_{i,j}<=threshold, otherwise w_{i,j}=0 If false wij=dij^{alpha} alpha : float distance decay parameter for weight (default -1.0) if alpha is positive the weights will not decline with distance. If binary is True, alpha is ignored ids : list values to use for keys of the neighbors and weights dicts build_sp : boolean True to build sparse distance matrix and false to build dense distance matrix; significant speed gains may be obtained dending on the sparsity of the of distance_matrix and threshold that is applied silent : boolean By default PySAL will print a warning if the dataset contains any disconnected observations or islands. To silence this warning set this parameter to True. Attributes ---------- weights : dict of neighbor weights keyed by observation id neighbors : dict of neighbors keyed by observation id Examples -------- >>> points=[(10, 10), (20, 10), (40, 10), (15, 20), (30, 20), (30, 30)] >>> wcheck = pysal.W({0: [1, 3], 1: [0, 3], 2: [], 3: [0, 1], 4: [5], 5: [4]}) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w=DistanceBand(points,threshold=11.2) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> pysal.weights.util.neighbor_equality(w, wcheck) True >>> w=DistanceBand(points,threshold=14.2) >>> wcheck = pysal.W({0: [1, 3], 1: [0, 3, 4], 2: [4], 3: [1, 0], 4: [5, 2, 1], 5: [4]}) >>> pysal.weights.util.neighbor_equality(w, wcheck) True inverse distance weights >>> w=DistanceBand(points,threshold=11.2,binary=False) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.10000000000000001, 0.089442719099991588] >>> w.neighbors[0] [1, 3] >>> gravity weights >>> w=DistanceBand(points,threshold=11.2,binary=False,alpha=-2.) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.01, 0.0079999999999999984] Notes ----- This was initially implemented running scipy 0.8.0dev (in epd 6.1). earlier versions of scipy (0.7.0) have a logic bug in scipy/sparse/dok.py so serge changed line 221 of that file on sal-dev to fix the logic bug. """ def __init__(self, data, threshold, p=2, alpha=-1.0, binary=True, ids=None, build_sp=True, silent=False): """Casting to floats is a work around for a bug in scipy.spatial. See detail in pysal issue #126. """ self.p = p self.threshold = threshold self.binary = binary self.alpha = alpha self.build_sp = build_sp self.silent = silent if isKDTree(data): self.kd = data self.data = self.kd.data else: if self.build_sp: try: data = np.asarray(data) if data.dtype.kind != 'f': data = data.astype(float) self.data = data self.kd = KDTree(self.data) except: raise ValueError("Could not make array from data") else: self.data = data self.kd = None self._band() neighbors, weights = self._distance_to_W(ids) W.__init__(self, neighbors, weights, ids, silent_island_warning=self.silent) @classmethod def from_shapefile(cls, filepath, threshold, idVariable=None, **kwargs): """ Distance-band based weights from shapefile Arguments --------- shapefile : string shapefile name with shp suffix idVariable : string name of column in shapefile's DBF to use for ids Returns -------- Kernel Weights Object See Also --------- :class: `pysal.weights.DistanceBand` :class: `pysal.weights.W` """ points = get_points_array_from_shapefile(filepath) if idVariable is not None: ids = get_ids(filepath, idVariable) else: ids = None return cls.from_array(points, threshold, ids=ids, **kwargs) @classmethod def from_array(cls, array, threshold, **kwargs): """ Construct a DistanceBand weights from an array. Supports all the same options as :class:`pysal.weights.DistanceBand` See Also -------- :class:`pysal.weights.DistanceBand` :class:`pysal.weights.W` """ return cls(array, threshold, **kwargs) @classmethod def from_dataframe(cls, df, threshold, geom_col='geometry', ids=None, **kwargs): """ Make DistanceBand weights from a dataframe. Parameters ---------- df : pandas.dataframe a dataframe with a geometry column that can be used to construct a W object geom_col : string column name of the geometry stored in df ids : string or iterable if string, the column name of the indices from the dataframe if iterable, a list of ids to use for the W if None, df.index is used. See Also -------- :class:`pysal.weights.DistanceBand` :class:`pysal.weights.W` """ pts = get_points_array(df[geom_col]) if ids is None: ids = df.index.tolist() elif isinstance(ids, str): ids = df[ids].tolist() return cls(pts, threshold, ids=ids, **kwargs) def _band(self): """Find all pairs within threshold. """ if self.build_sp: self.dmat = self.kd.sparse_distance_matrix( self.kd, max_distance=self.threshold).tocsr() else: if str(self.kd).split('.')[-1][0:10] == 'Arc_KDTree': raise TypeError('Unable to calculate dense arc distance matrix;' ' parameter "build_sp" must be set to True for arc' ' distance type weight') self.dmat = self._spdistance_matrix(self.data, self.data, self.threshold) def _distance_to_W(self, ids=None): if self.binary: self.dmat[self.dmat>0] = 1 self.dmat.eliminate_zeros() tempW = WSP2W(WSP(self.dmat), silent_island_warning=self.silent) neighbors = tempW.neighbors weight_keys = tempW.weights.keys() weight_vals = tempW.weights.values() weights = dict(zip(weight_keys, map(list, weight_vals))) return neighbors, weights else: weighted = self.dmat.power(self.alpha) weighted[weighted==np.inf] = 0 weighted.eliminate_zeros() tempW = WSP2W(WSP(weighted), silent_island_warning=self.silent) neighbors = tempW.neighbors weight_keys = tempW.weights.keys() weight_vals = tempW.weights.values() weights = dict(zip(weight_keys, map(list, weight_vals))) return neighbors, weights def _spdistance_matrix(self, x,y, threshold=None): dist = distance_matrix(x,y) if threshold is not None: zeros = dist > threshold dist[zeros] = 0 return sp.csr_matrix(dist)
class DistanceBand(W): """ Spatial weights based on distance band. Parameters ---------- data : array (n,k) or KDTree where KDtree.data is array (n,k) n observations on k characteristics used to measure distances between the n objects threshold : float distance band p : float Minkowski p-norm distance metric parameter: 1<=p<=infinity 2: Euclidean distance 1: Manhattan distance binary : boolean If true w_{ij}=1 if d_{i,j}<=threshold, otherwise w_{i,j}=0 If false wij=dij^{alpha} alpha : float distance decay parameter for weight (default -1.0) if alpha is positive the weights will not decline with distance. If binary is True, alpha is ignored ids : list values to use for keys of the neighbors and weights dicts build_sp : boolean True to build sparse distance matrix and false to build dense distance matrix; significant speed gains may be obtained dending on the sparsity of the of distance_matrix and threshold that is applied silent : boolean By default PySAL will print a warning if the dataset contains any disconnected observations or islands. To silence this warning set this parameter to True. Attributes ---------- weights : dict of neighbor weights keyed by observation id neighbors : dict of neighbors keyed by observation id Examples -------- >>> points=[(10, 10), (20, 10), (40, 10), (15, 20), (30, 20), (30, 30)] >>> wcheck = pysal.W({0: [1, 3], 1: [0, 3], 2: [], 3: [0, 1], 4: [5], 5: [4]}) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w=DistanceBand(points,threshold=11.2) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> pysal.weights.util.neighbor_equality(w, wcheck) True >>> w=DistanceBand(points,threshold=14.2) >>> wcheck = pysal.W({0: [1, 3], 1: [0, 3, 4], 2: [4], 3: [1, 0], 4: [5, 2, 1], 5: [4]}) >>> pysal.weights.util.neighbor_equality(w, wcheck) True inverse distance weights >>> w=DistanceBand(points,threshold=11.2,binary=False) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.10000000000000001, 0.089442719099991588] >>> w.neighbors[0] [1, 3] >>> gravity weights >>> w=DistanceBand(points,threshold=11.2,binary=False,alpha=-2.) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.01, 0.0079999999999999984] Notes ----- This was initially implemented running scipy 0.8.0dev (in epd 6.1). earlier versions of scipy (0.7.0) have a logic bug in scipy/sparse/dok.py so serge changed line 221 of that file on sal-dev to fix the logic bug. """ def __init__(self, data, threshold, p=2, alpha=-1.0, binary=True, ids=None, build_sp=True, silent=False): """Casting to floats is a work around for a bug in scipy.spatial. See detail in pysal issue #126. """ if ids is not None: ids = list(ids) self.p = p self.threshold = threshold self.binary = binary self.alpha = alpha self.build_sp = build_sp self.silent = silent if isKDTree(data): self.kd = data self.data = self.kd.data else: if self.build_sp: try: data = np.asarray(data) if data.dtype.kind != 'f': data = data.astype(float) self.data = data self.kd = KDTree(self.data) except: raise ValueError("Could not make array from data") else: self.data = data self.kd = None self._band() neighbors, weights = self._distance_to_W(ids) W.__init__(self, neighbors, weights, ids, silent_island_warning=self.silent) @classmethod def from_shapefile(cls, filepath, threshold, idVariable=None, **kwargs): """ Distance-band based weights from shapefile Arguments --------- shapefile : string shapefile name with shp suffix idVariable : string name of column in shapefile's DBF to use for ids Returns -------- Kernel Weights Object See Also --------- :class: `pysal.weights.DistanceBand` :class: `pysal.weights.W` """ points = get_points_array_from_shapefile(filepath) if idVariable is not None: ids = get_ids(filepath, idVariable) else: ids = None return cls.from_array(points, threshold, ids=ids, **kwargs) @classmethod def from_array(cls, array, threshold, **kwargs): """ Construct a DistanceBand weights from an array. Supports all the same options as :class:`pysal.weights.DistanceBand` See Also -------- :class:`pysal.weights.DistanceBand` :class:`pysal.weights.W` """ return cls(array, threshold, **kwargs) @classmethod def from_dataframe(cls, df, threshold, geom_col='geometry', ids=None, **kwargs): """ Make DistanceBand weights from a dataframe. Parameters ---------- df : pandas.dataframe a dataframe with a geometry column that can be used to construct a W object geom_col : string column name of the geometry stored in df ids : string or iterable if string, the column name of the indices from the dataframe if iterable, a list of ids to use for the W if None, df.index is used. See Also -------- :class:`pysal.weights.DistanceBand` :class:`pysal.weights.W` """ pts = get_points_array(df[geom_col]) if ids is None: ids = df.index.tolist() elif isinstance(ids, str): ids = df[ids].tolist() else: ids = df.index.tolist() return cls(pts, threshold, ids=ids, **kwargs) def _band(self): """Find all pairs within threshold. """ if self.build_sp: self.dmat = self.kd.sparse_distance_matrix( self.kd, max_distance=self.threshold, p=self.p).tocsr() else: if str(self.kd).split('.')[-1][0:10] == 'Arc_KDTree': raise TypeError( 'Unable to calculate dense arc distance matrix;' ' parameter "build_sp" must be set to True for arc' ' distance type weight') self.dmat = self._spdistance_matrix(self.data, self.data, self.threshold) def _distance_to_W(self, ids=None): if self.binary: self.dmat[self.dmat > 0] = 1 self.dmat.eliminate_zeros() tempW = WSP2W(WSP(self.dmat, id_order=ids), silent_island_warning=self.silent) neighbors = tempW.neighbors weight_keys = list(tempW.weights.keys()) weight_vals = list(tempW.weights.values()) weights = dict(list(zip(weight_keys, list(map(list, weight_vals))))) return neighbors, weights else: weighted = self.dmat.power(self.alpha) weighted[weighted == np.inf] = 0 weighted.eliminate_zeros() tempW = WSP2W(WSP(weighted, id_order=ids), silent_island_warning=self.silent) neighbors = tempW.neighbors weight_keys = list(tempW.weights.keys()) weight_vals = list(tempW.weights.values()) weights = dict(list(zip(weight_keys, list(map(list, weight_vals))))) return neighbors, weights def _spdistance_matrix(self, x, y, threshold=None): dist = distance_matrix(x, y) if threshold is not None: zeros = dist > threshold dist[zeros] = 0 return sp.csr_matrix(dist)
class DistanceBand(W): """Spatial weights based on distance band Parameters ---------- data : array (n,k) or KDTree where KDtree.data is array (n,k) n observations on k characteristics used to measure distances between the n objects threshold : float distance band p : float Minkowski p-norm distance metric parameter: 1<=p<=infinity 2: Euclidean distance 1: Manhattan distance binary : binary If true w_{ij}=1 if d_{i,j}<=threshold, otherwise w_{i,j}=0 If false wij=dij^{alpha} alpha : float distance decay parameter for weight (default -1.0) if alpha is positive the weights will not decline with distance. If binary is True, alpha is ignored Examples -------- >>> points=[(10, 10), (20, 10), (40, 10), (15, 20), (30, 20), (30, 30)] >>> w=DistanceBand(points,threshold=11.2) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights {0: [1, 1], 1: [1, 1], 2: [], 3: [1, 1], 4: [1], 5: [1]} >>> w.neighbors {0: [1, 3], 1: [0, 3], 2: [], 3: [0, 1], 4: [5], 5: [4]} >>> w=DistanceBand(points,threshold=14.2) >>> w.weights {0: [1, 1], 1: [1, 1, 1], 2: [1], 3: [1, 1], 4: [1, 1, 1], 5: [1]} >>> w.neighbors {0: [1, 3], 1: [0, 3, 4], 2: [4], 3: [0, 1], 4: [1, 2, 5], 5: [4]} inverse distance weights >>> w=DistanceBand(points,threshold=11.2,binary=False) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.10000000000000001, 0.089442719099991588] >>> w.neighbors[0] [1, 3] >>> gravity weights >>> w=DistanceBand(points,threshold=11.2,binary=False,alpha=-2.) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.01, 0.0079999999999999984] Notes ----- this was initially implemented running scipy 0.8.0dev (in epd 6.1). earlier versions of scipy (0.7.0) have a logic bug in scipy/sparse/dok.py so serge changed line 221 of that file on sal-dev to fix the logic bug """ def __init__(self, data, threshold, p=2, alpha=-1.0, binary=True, ids=None): """ Casting to floats is a work around for a bug in scipy.spatial. See detail in pysal issue #126 """ if issubclass(type(data), scipy.spatial.KDTree): self.kd = data self.data = self.kd.data else: try: data = np.asarray(data) if data.dtype.kind != 'f': data = data.astype(float) self.data = data self.kd = KDTree(self.data) except: raise ValueError("Could not make array from data") self.p = p self.threshold = threshold self.binary = binary self.alpha = alpha self._band() neighbors, weights = self._distance_to_W(ids) W.__init__(self, neighbors, weights, ids) def _band(self): """ find all pairs within threshold """ kd = self.kd #ns=[kd.query_ball_point(point,self.threshold) for point in self.data] ns = kd.query_ball_tree(kd, self.threshold) self._nmat = ns def _distance_to_W(self, ids=None): allneighbors = {} weights = {} if ids: ids = np.array(ids) else: ids = np.arange(len(self._nmat)) if self.binary: for i, neighbors in enumerate(self._nmat): ns = [ni for ni in neighbors if ni != i] neigh = list(ids[ns]) if len(neigh) == 0: allneighbors[ids[i]] = [] weights[ids[i]] = [] else: allneighbors[ids[i]] = neigh weights[ids[i]] = [1] * len(ns) else: self.dmat = self.kd.sparse_distance_matrix( self.kd, max_distance=self.threshold) for i, neighbors in enumerate(self._nmat): ns = [ni for ni in neighbors if ni != i] neigh = list(ids[ns]) if len(neigh) == 0: allneighbors[ids[i]] = [] weights[ids[i]] = [] else: try: allneighbors[ids[i]] = neigh weights[ids[i]] = [self.dmat[( i, j)] ** self.alpha for j in ns] except ZeroDivisionError, e: print(e, "Cannot compute inverse distance for elements at same location (distance=0).") return allneighbors, weights
class DistanceBand(W): """ Spatial weights based on distance band. Parameters ---------- data : array (n,k) or KDTree where KDtree.data is array (n,k) n observations on k characteristics used to measure distances between the n objects threshold : float distance band p : float Minkowski p-norm distance metric parameter: 1<=p<=infinity 2: Euclidean distance 1: Manhattan distance binary : boolean If true w_{ij}=1 if d_{i,j}<=threshold, otherwise w_{i,j}=0 If false wij=dij^{alpha} alpha : float distance decay parameter for weight (default -1.0) if alpha is positive the weights will not decline with distance. If binary is True, alpha is ignored ids : list values to use for keys of the neighbors and weights dicts Examples -------- >>> points=[(10, 10), (20, 10), (40, 10), (15, 20), (30, 20), (30, 30)] >>> w=DistanceBand(points,threshold=11.2) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights {0: [1, 1], 1: [1, 1], 2: [], 3: [1, 1], 4: [1], 5: [1]} >>> w.neighbors {0: [1, 3], 1: [0, 3], 2: [], 3: [1, 0], 4: [5], 5: [4]} >>> w=DistanceBand(points,threshold=14.2) >>> w.weights {0: [1, 1], 1: [1, 1, 1], 2: [1], 3: [1, 1], 4: [1, 1, 1], 5: [1]} >>> w.neighbors {0: [1, 3], 1: [0, 3, 4], 2: [4], 3: [1, 0], 4: [5, 1, 2], 5: [4]} inverse distance weights >>> w=DistanceBand(points,threshold=11.2,binary=False) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.10000000000000001, 0.089442719099991588] >>> w.neighbors[0] [1, 3] >>> gravity weights >>> w=DistanceBand(points,threshold=11.2,binary=False,alpha=-2.) WARNING: there is one disconnected observation (no neighbors) Island id: [2] >>> w.weights[0] [0.01, 0.0079999999999999984] Notes ----- This was initially implemented running scipy 0.8.0dev (in epd 6.1). earlier versions of scipy (0.7.0) have a logic bug in scipy/sparse/dok.py so serge changed line 221 of that file on sal-dev to fix the logic bug. """ def __init__(self, data, threshold, p=2, alpha=-1.0, binary=True, ids=None): """Casting to floats is a work around for a bug in scipy.spatial. See detail in pysal issue #126. """ if issubclass(type(data), scipy.spatial.KDTree): self.kd = data self.data = self.kd.data else: try: data = np.asarray(data) if data.dtype.kind != 'f': data = data.astype(float) self.data = data self.kd = KDTree(self.data) except: raise ValueError("Could not make array from data") self.p = p self.threshold = threshold self.binary = binary self.alpha = alpha self._band() neighbors, weights = self._distance_to_W(ids) W.__init__(self, neighbors, weights, ids) def _band(self): """Find all pairs within threshold. """ self.dmat = self.kd.sparse_distance_matrix( self.kd, max_distance=self.threshold) def _distance_to_W(self, ids=None): if ids: ids = np.array(ids) else: ids = np.arange(self.dmat.shape[0]) neighbors = dict([(i,[]) for i in ids]) weights = dict([(i,[]) for i in ids]) if self.binary: for key,weight in self.dmat.items(): i,j = key if j not in neighbors[i]: weights[i].append(1) neighbors[i].append(j) if i not in neighbors[j]: weights[j].append(1) neighbors[j].append(i) else: for key,weight in self.dmat.items(): i,j = key if j not in neighbors[i]: weights[i].append(weight**self.alpha) neighbors[i].append(j) if i not in neighbors[j]: weights[j].append(weight**self.alpha) neighbors[j].append(i) return neighbors, weights