标记数据类型Python

时间:2016-06-24 17:17:48

标签: python numpy pandas

我正在计算点和多个线段之间的测地距离。每个线段都有唯一的识别号。我希望从距离函数返回距离,使它们本质上绑在一起。我还希望保持功能,如对距离进行排序,并使用标签或位置对其进行索引,并返回距离数据和标签。像带有索引的Pandas系列之类的东西,但是我不能使用系列,因为数据被返回到Pandas DataFrame中,然后扩展系列并使其变得混乱。这是一个例子:

In [1]: '''Note that all this happens inside an apply function of a Pandas Series'''
        labels = [25622, 25621, 25620, 25619, 25618]
        dist = vect_dist_funct(pt, labels) #vect_dist_funct does the computations, and returns distances in meters
        dist
Out[1]: array([296780.2217658355, 296572.4476883276, 296364.21166884096,
               296156.4366241771, 295948.6610171968], dtype=object)

然而,我想要的是这样的字典,标签和距离固有地相互联系:

{25622 : 296780.2217658355,
 25621 : 296572.4476883276,
 25620 : 296364.21166884096,
 25619 : 296156.4366241771,
 25618 : 295948.6610171968}

但现在我失去了价值观的功能。我不能轻易地对它们进行排序,或者比较它们,或者任何东西。我看了Numpy Structured Arrays,它们似乎可行,但是如果我无法对距离进行排序,并得到最近段的索引,那对我来说就没那么大了。我可以使用其他任何数据类型吗?

长篇故事和背景

我正在尝试进行空间连接。通过在RTree中搜索(example),我得到了一个点最有可能更接近的段的索引。这些是标签中的索引。然后,我查看线几何表,找到所选标签的线几何,并计算每个线段的点距离。

后续步骤涉及检查空间连接的完整性。在某些情况下,最近的不是最佳连接候选者,并且需要在其他参数上评估连接。因此,我的计划是从最近的部分向外工作。其中包括对距离进行排序,获取最近段的索引,然后使用该索引查看段表并提取该行的其他属性以供检查。如果可以确认匹配,则接受所述段,否则拒绝该算法,并且算法将移动到下一个最接近的段。

执行所有这些操作的数据类型是我正在寻找的,而不会破坏计算它的段之间的距离。

使用Pandas的问题

这就是实际调用函数的方式:

joined = points['geometry'].apply(pointer, centroid=line['centroid'], tree_idx=tree_idx))

然后在pointer内,会发生这种情况:

def pointer(point, centroid, tree_idx):
    intersect = list(tree_idx.intersection(point.bounds))
    if len(intersect) > 0:
        points = pd.Series([point.coords[0]]*len(intersect)).values
        polygons = centroid.loc[intersect].values
        dist = vect_dist_funct(points, polygons)
        return pd.Series(dist, index=intercept, name='Dist').sort_values()
    else:
        return pd.Series(np.nan, index=[0], name='Dist')

然后,joined看起来像这样:

There is no point in copying the table, I guess.

这是因为不计算所有点(行是点)和所有行(列是行)之间的距离。这太昂贵了(4M点,每个状态180k行,整个数据集50个状态)。此外,与返回两个Numpy数组时相比,此生成joined的DataFrame合并操作会将运行时间增加7倍。返回两个Numpy数组的问题是,保持距离和线ID始终保持一致并不容易。

Points,Lines,tree_idx

的示例

请注意,这是列和行中的截断数据集。我只包括相关列,而不包括其他数据:

分:

                        geometry
id      
88400001394219  0.00    POINT (-105.2363291 39.6988139)
                0.25    POINT (-105.2372017334178 39.69899060448157)
                0.50    POINT (-105.2380177896182 39.69933953105642)
                0.75    POINT (-105.2387202141595 39.69988447162143)
                1.00    POINT (-105.2393222 39.7005405)
88400002400701  0.00    POINT (-104.7102833 39.8318348)
                0.25    POINT (-104.7102827 39.831966625)
                0.50    POINT (-104.7102821 39.83209845)
                0.75    POINT (-104.7102815 39.832230275)
                1.00    POINT (-104.7102809 39.8323621)

所以这基本上是线上的插值点。行id是索引的第一级,第二级是插值点的百分比。这形成了第一个数据集,即我想从第二个数据集中带来一些属性的数据集。

行:

        geometry                                            centroid
id      
71345   POLYGON ((-103.2077992965318 40.58026765162965...   (-103.20073265160862, 40.576450381964975)
71346   POLYGON ((-103.2069505830457 40.58155121711739...   (-103.19987394433825, 40.57774903464972)
71347   POLYGON ((-103.2061017677045 40.58283487609803...   (-103.19901204453959, 40.57905245493993)
71348   POLYGON ((-103.2052000154291 40.58419853220472...   (-103.19815200508097, 40.58035300329024)
71349   POLYGON ((-103.2043512639656 40.58548197865339...   (-103.19729445792181, 40.58164972491414)
71350   POLYGON ((-103.2035025651746 40.5867652936463,...   (-103.1964362470977, 40.5829473948391)
71351   POLYGON ((-103.2026535431035 40.58804903349249...   (-103.19557847342394, 40.58424434094705)
71352   POLYGON ((-103.201804801526 40.58933229190573,...   (-103.19472966696722, 40.58552767098465)
71353   POLYGON ((-103.2009557884142 40.59061590473365...   (-103.19388484652855, 40.58680427447224)
71354   POLYGON ((-103.2001001699726 40.59190793446012...   (-103.19303392095904, 40.5880882237994)

这是第二个数据集的一部分(本答案开头提到的标签是此数据集的索引)。目标是以智能方式将属性从此数据集传输到点数据集。第一步是找到每个点的最近线。然后我将比较点数据集中的一些属性和线数据集,并确认或拒绝连接,就像我提到的那样。

tree_idx:

使用以下代码创建tree_idx:

import rtree
lines_bounds = lines['geometry'].apply(lambda x: x.bounds)
tree_idx = rtree.index.Index()
for i in lines_bounds.index:
    tree_idx.insert(i, lines_bounds.loc[i])

3 个答案:

答案 0 :(得分:1)

所以我认为您的整体问题是您正在创建一个DataFrame,其中列标签是intercept值。我想你想要做的是创建一个DataFrame,其中一列包含截距值,而另一列包含距离。我将尝试为您提供我认为有用的代码,但是如果没有原始数据就很难确定,因此您需要对其进行一些修改才能使其完美运行。

首先,我会修改vect_dist_funct所以如果第一个参数是标量,它会创建正确长度的列表,如果第二个参数为空,则返回NaN

接下来,我将所有有用的值作为列添加到DataFrame中:

points['intersect'] = points['geometry'].apply(lambda x: np.array(tree_idx.intersection(x.bounds)))
points['polygons'] = points['intersect'].apply(lambda x: centroid.loc[x].values)
points['coords0'] = points['geometry'].apply(lambda x: x.coords[0])
points['dist'] = points.apply(lambda x: vect_dist_funct(x.coords0, x.polygons), axis=1)

这将为您提供一个包含所有距离的列。如果你真的希望可以访问截距值,那么你可以创建一个只有截距和距离的DataFrame,然后将截距作为另一个多索引级别来避免过多的NaN值:

pairs = points.apply(lambda x: pd.DataFrame([x['intersect'], x['dist']], index=['intersect', 'dist']).T.stack(), axis=1)
pairs = pairs.stack(level=0).set_index('intersect', append=True)
pairs.index = pairs.index.droplevel(level=2)

这应该给你一个Series,其中第一个索引是id,第二个是百分比,第三个是交叉,值是距离。

答案 1 :(得分:0)

所以,我认为索引是标签的数据框可能是最简单的

distances = {25622 : 296780.2217658355,
 25621 : 296572.4476883276,
 25620 : 296364.21166884096,
 25619 : 296156.4366241771,
 25618 : 295948.6610171968}

df = pd.DataFrame([tup for tup in distances.items()],columns=["label", "dist"]).sort_values('dist').set_index('label')
df

输出:

    dist
label   
25618   295948.661017
25619   296156.436624
25620   296364.211669
25621   296572.447688
25622   296780.221766

然后,如果您想按标签名称访问距离

df.loc[25620]
Out:
dist    296364.211669
Name: 25620, dtype: float64

然后,如果你想找到标签附近'那一点,您可以使用

获取行号
row_num = df.index.get_loc(25620)
print(row_num)
Out: 2

然后你可以访问"附近"点df.iloc[row_number]

df.iloc[3]
Out: 
dist    296572.447688
Name: 25621, dtype: float64

这涵盖了你需要的一切吗?

答案 2 :(得分:0)

在完成所有事情后,在尝试使TheBlackCat的答案工作约3小时后,我决定使用xarray。所以现在pointer函数看起来像这样:

def pointer(point, centroid, tree_idx):
    intersect = list(tree_idx.intersection(point.bounds))
    if len(intersect) > 0:
        points = pd.Series([point.coords[0]]*len(intersect)).values
        polygons = centroid.loc[intersect].values
        dist = vect_dist_funct(points, polygons)
        sorter = np.argsort(dist)
        return xr.DataArray(dist[sorter], [('dim0', np.asarray(intersect)[sorter])])
    else:
        return xr.DataArray(np.nan)

完成。这符合我的需要。我有距离和它们一起计算的段ID,这样一个转换就会影响另一个。并且距离仍然可以操作,xarray还为我提供了分组,合并等方面的高级功能。

此外,在一个州的0.1%数据上运行大约需要一分钟,对于10%的数据需要10分钟。因此,我预计100%的数据大约是100分钟。但老实说,即使一个州需要3个小时,我仍然可以在一天内完成所有50个州(在16核服务器上使用多线程)。所以我暂时对此很满意。感谢我得到的所有建议。特别是@TheBlackCat,@ michael_j_ward和@hpaulj。