问题描述
我需要将 Shapely MultiPoints 的 dict 转换为数据帧。我已经编写了一个双循环程序来做到这一点,但我想知道是否有更好的方法来做到这一点。
示例数据和当前代码:
object.bookmark
如果有点慢和笨重,这是有效的。这是否可以做得更好,如果可以,如何做?
解决方法
构建框架构造函数的列表理解可能是这里的最佳选择:
df = pd.DataFrame(
[[k,point.x,point.y]
for k,v in data.items()
for point in wkb.loads(v,hex=True)],columns=['ID','X','Y']
)
ID X Y
0 A 3.0 5.0
1 A 3.0 3.0
2 B -141.0 820.0
3 B 910.0 -332.0
4 C 5102.0 7020.0
5 C 30.0 -20020.0
pandas
操作在这里会很昂贵,尤其是循环中的 append
,它需要在每次迭代中生成 DataFrame 的副本。
一些来自 %timeit
的时间信息:
这个答案
def fn(data):
return pd.DataFrame(
[[k,point.y]
for k,v in data.items()
for point in wkb.loads(v,'Y']
)
%timeit fn(data)
552 µs ± 11.2 µs per loop (mean ± std. dev. of 7 runs,1000 loops each)
def fn2(data):
df = pd.DataFrame(columns=["ID","X","Y"])
for key,wkb_val in data.items():
for point in wkb.loads(wkb_val,hex=True):
df = df.append({
"ID": key,"X": point.x,"Y": point.y
},ignore_index=True)
return df
%timeit fn2(data)
10.3 ms ± 77.4 µs per loop (mean ± std. dev. of 7 runs,100 loops each)
def fn3(data):
return pd.concat(
(
(
pd.concat(
(pd.Series({"ID": key,"Y": point.y}) for
point in
wkb.loads(wkb_val,hex=True)),axis=1)
)
for key,wkb_val in data.items()
),axis=1
).T
%timeit fn3(data)
3.42 ms ± 132 µs per loop (mean ± std. dev. of 7 runs,100 loops each)
,
性能缓慢的原因是每次执行 df = df.append(...)
时,您都在创建一个新的 DataFrame 并复制所有现有行。
这个解决方案看起来有点笨拙,但我相信它会奏效。
df = pd.concat(
(
(
pd.concat((pd.Series({"ID": key,"Y": point.y}) for point in wkb.loads(wkb_val,axis=1)
)
for key,wkb_val in data.items()
),axis=1
).T
最后的 .T
转置 DataFrame,否则会创建一个宽 DataFrame,其中 ID、X 和 Y 作为索引而不是列。