我想在Polars中执行以下python代码行作为UDF:
w = wkt.loads('POLYGON((-160.043334960938 70.6363054807905, -160.037841796875 70.6363054807905, -160.037841796875 70.6344840663086, -160.043334960938 70.6344840663086, -160.043334960938 70.6363054807905))')
polygon (optionally including holes).
j = shapely.geometry.mapping(w)
h3.polyfill(j, res=10, geo_json_conformant=True)
Pandas/地Pandas:
import pandas as pd
import geopandas as gpd
import polars as pl
from shapely import wkt
pandas_df = pd.DataFrame({'quadkey': {0: '0022133222330023',
1: '0022133222330031',
2: '0022133222330100'},
'tile': {0: 'POLYGON((-160.043334960938 70.6363054807905, -160.037841796875 70.6363054807905, -160.037841796875 70.6344840663086, -160.043334960938 70.6344840663086, -160.043334960938 70.6363054807905))',
1: 'POLYGON((-160.032348632812 70.6381267305321, -160.02685546875 70.6381267305321, -160.02685546875 70.6363054807905, -160.032348632812 70.6363054807905, -160.032348632812 70.6381267305321))',
2: 'POLYGON((-160.02685546875 70.6417687358462, -160.021362304688 70.6417687358462, -160.021362304688 70.6399478155463, -160.02685546875 70.6399478155463, -160.02685546875 70.6417687358462))'},
'avg_d_kbps': {0: 15600, 1: 6790, 2: 9619},
'avg_u_kbps': {0: 14609, 1: 22363, 2: 15757},
'avg_lat_ms': {0: 168, 1: 68, 2: 92},
'tests': {0: 2, 1: 1, 2: 6},
'devices': {0: 1, 1: 1, 2: 1}}
)
# display(pandas_df)
gdf = pandas_df.copy()
gdf['geometry'] = gpd.GeoSeries.from_wkt(pandas_df['tile'])
import h3pandas
display(gdf.h3.polyfill_resample(10))
这工作起来超级快和容易。然而,从Pandas应用程序调用的polyfill函数作为UDF对于我的数据集的大小来说太慢了。
相反,我很想使用极线,但我遇到了几个问题:
geo类型无法理解
为了更好的表现而努力转向极地
pl.from_pandas(gdf)
失败,并显示:箭头类型错误:未传递numpy. dtype对象
这看起来像geoarrow/geoparquet是不支持的极性
numpy矢量化极坐标接口因缺少几何类型而失败
polars_df = pl.from_pandas(pandas_df)
out = polars_df.select(
[
gpd.GeoSeries.from_wkt(pl.col('tile')),
]
)
失败:
TypeError: 'data' should be array of geometry objects. Use from_shapely, from_wkb, from_wkt functions to construct a GeometryArray.
全部手工制作
polars_df.with_column(pl.col('tile').map(lambda x: h3.polyfill(shapely.geometry.mapping(wkt.loads(x)), res=10, geo_json_conformant=True)).alias('geometry'))
失败:
Conversion of polars data type Utf8 to C-type not implemented.
最后一个选项看起来是最有希望的(没有特殊的地理空间类型的错误)。但是这个字符串/Utf8类型的C没有被实现的一般错误消息对我来说听起来很奇怪。
此外:
polars_df.select(pl.col('tile').apply(lambda x: h3.polyfill(shapely.geometry.mapping(wkt.loads(x)), res=10, geo_json_conformant=True)))
工作-但缺少其他列-即手动选择这些列的语法不方便。但在附加以下内容时也会失败:
.explode('tile').collect()
# InvalidOperationError: cannot explode dtype: Object("object")
2条答案
按热度按时间umuewwlo1#
要解决一些极坐标错误:
wkt
函数不能处理pl.Series
-你可以使用.to_numpy()
来提供一个numpy数组:您可以使用
.with_columns()
代替.select()
:一个二个一个一个
h3.polyfill()
正在返回一个python set对象,polars实际上无法"识别"该对象。您可以将集合转换为
list()
,极坐标将为您提供list[str]
列,而不是object
-您可以.explode()
而不会出错。与在Pandas身上进行"全手工"的方法相比,可能没有太大区别:
okxuctiv2#
Polars的优势在于数据存储在类型为inflexible arrow2的数组中,并且计算得到了优化(类似于一个数据库查询优化器)并在rust中运行,任何时候你在polars中使用
apply
,你就会失去polars的好处,因为它会把函数发送回python,而不是在rust中优化和计算。Polars doesn't support anything that looks like a shapely geometry也没有内置地理空间几何操作符。还有geopolars,它还处于绝对的婴儿期,可能还不是特别有用,长话短说,polars(在python中)还不能帮助geo计算。
回到您最初的问题,如果您不使用
gdf.h3.polyfill_resample(10)
,而是使用类似这样的代码(强调 * 类似 * 的代码,因为我对h3
不是很熟悉)您可能需要研究
mapping(gdf.geometry)
返回的dict,以获得符合h3使用的geojson输入的内容。这个想法是,将整个输入直接馈送到h3将(至少有可能,我不知道它的内部结构)允许它在C中执行所有的循环和迭代,而不是在python中执行循环,这是你在
apply
中得到的。