将 Shapely Multipoint 转换为 Pandas Dataframe 的优雅方式
Elegant way to convert Shapely Multipoint to a Pandas Dataframe
我需要将 Shapely MultiPoints 的字典转换为数据框。我已经编写了一个双循环程序来执行此操作,但我想知道是否有更好的方法来执行此操作。
示例数据和当前代码:
from shapely import wkb
import pandas as pd
data = {
"A": "010400000002000000010100000000000000000008400000000000001440010100000000000000000008400000000000000840",
"B": "01040000000200000001010000000000000000A061C00000000000A0894001010000000000000000708C400000000000C074C0",
"C": "01040000000200000001010000000000000000EEB34000000000006CBB4001010000000000000000003E4000000000008DD3C0"
}
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)
如果有点慢和笨重,这很有效。可以做得更好吗?如果可以,怎么做?
性能缓慢的原因是每次 df = df.append(...)
,您都在创建一个新的 DataFrame 并复制所有现有行。
这个解决方案看起来有点笨拙,但我相信它会奏效。
df = pd.concat(
(
(
pd.concat((pd.Series({"ID": key, "X": point.x, "Y": point.y}) for point in wkb.loads(wkb_val, hex=True)), axis=1)
)
for key, wkb_val in data.items()
), axis=1
).T
最后的 .T
转置 DataFrame,否则会创建一个宽 DataFrame,其中 ID、X 和 Y 作为索引而不是列。
构建框架构造函数的列表理解可能是此处的最佳选择:
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.x, point.y]
for k, v in data.items()
for point in wkb.loads(v, hex=True)],
columns=['ID', 'X', '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, "X": point.x, "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)
我需要将 Shapely MultiPoints 的字典转换为数据框。我已经编写了一个双循环程序来执行此操作,但我想知道是否有更好的方法来执行此操作。
示例数据和当前代码:
from shapely import wkb
import pandas as pd
data = {
"A": "010400000002000000010100000000000000000008400000000000001440010100000000000000000008400000000000000840",
"B": "01040000000200000001010000000000000000A061C00000000000A0894001010000000000000000708C400000000000C074C0",
"C": "01040000000200000001010000000000000000EEB34000000000006CBB4001010000000000000000003E4000000000008DD3C0"
}
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)
如果有点慢和笨重,这很有效。可以做得更好吗?如果可以,怎么做?
性能缓慢的原因是每次 df = df.append(...)
,您都在创建一个新的 DataFrame 并复制所有现有行。
这个解决方案看起来有点笨拙,但我相信它会奏效。
df = pd.concat(
(
(
pd.concat((pd.Series({"ID": key, "X": point.x, "Y": point.y}) for point in wkb.loads(wkb_val, hex=True)), axis=1)
)
for key, wkb_val in data.items()
), axis=1
).T
最后的 .T
转置 DataFrame,否则会创建一个宽 DataFrame,其中 ID、X 和 Y 作为索引而不是列。
构建框架构造函数的列表理解可能是此处的最佳选择:
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.x, point.y]
for k, v in data.items()
for point in wkb.loads(v, hex=True)],
columns=['ID', 'X', '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, "X": point.x, "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)