对 pandas 数据框进行窗口化操作,以列出与前 n 个条目的欧氏距离
A windowed operation on a pandas data frame to list Euclidean distance from the previous n entries
我有一个已排序的(在 'values' 上)数据框,如下所示。未命名的列是索引。
x_cord y_cord value
3384209 1650 1741 0.009752
3382265 1650 1740 0.009481
3384208 1649 1741 0.008943
3382264 1649 1740 0.008676
3384210 1651 1741 0.008473
... ... ... ...
1679661 46 865 0.000000
1679660 45 865 0.000000
1679659 44 865 0.000000
1679658 43 865 0.000000
5038847 1944 2592 0.000000
如何创建另一个列,其中包含到前 n 行的欧氏距离列表?例如
- 第一行将有一个空列表
- 第二行将列出第一行和第二行之间的距离(参见坐标),即 1 项。
- 第三排会有。两个项目的列表,即第三个和第二个之间
以及第三和第一。
- 第 21 行将包含十个项目的列表,其自身与前九个点之间的欧氏距离。
该列表始终最多包含十(或 n)个元素。
我怎样才能做到这一点?
仅供参考
def euc_distance(x1, y1, x2, y2):
return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
首先,移动所有前 10 行,在每个移动的专用列中:
for i in range(1,11):
df["x_cord_"+str(i)] = df["x_cord"].shift(i)
df["y_cord_"+str(i)] = df["y_cord"].shift(i)
然后,计算每一行与现在存储在其专用列中的其他 10 个坐标之间的距离。 if
确保如果列中有 Nan
,则结果列表将不包含此值。
df["distance"] = df.apply(lambda row: [euc_distance(row["x_cord"], row["y_cord"], row["x_cord_"+str(i)], row["y_cord_"+str(i)]) for i in range(1,11) if not math.isnan(row["x_cord_"+str(i)])], axis=1)
最后,删除仅为计算创建的列。
df = df[["x_cord", "y_cord", "value", "distance"]]
输出:
x_cord y_cord value distance
3384209 1650 1741 0.009752 []
3382265 1650 1740 0.009481 [1.0]
3384208 1649 1741 0.008943 [1.4142135623730951, 1.0]
3382264 1649 1740 0.008676 [1.0, 1.0, 1.4142135623730951]
3384210 1651 1741 0.008473 [2.23606797749979, 2.0, 1.4142135623730951, 1.0]
可能还可以改进。
Numpy 助你一臂之力! (快速 解决方案,主要是矢量化):
def fun(k, z):
na = np.full((k, z.shape[1]), np.nan)
a = np.row_stack((na, z[:-k, :]))
return np.linalg.norm(z - a, axis=1)
vfun = np.vectorize(fun, signature='(),(n,m)->(n)')
现在,您可以获得包含所有距离的数组 (n, k)
:
>>> k = 4 # just for nice printing; replace with 10 in your setting
>>> z = pd.DataFrame(vfun(range(1, k+1), df[['x_cord', 'y_cord']].values).T)
... z
0 1 2 3
0 NaN NaN NaN NaN
1 1.000000 NaN NaN NaN
2 1.414214 1.000000 NaN NaN
3 1.000000 1.000000 1.414214 NaN
4 2.236068 2.000000 1.414214 1.000000
5 1828.496924 1826.262303 1826.741635 1827.140115
6 1.000000 1829.374757 1827.140115 1827.619216
7 1.000000 2.000000 1830.252715 1828.018052
8 1.000000 2.000000 3.000000 1831.130798
9 2568.332144 2567.592063 2566.852158 2566.112429
如果您愿意,可以将其转换为列表:
>>> z.apply(list, axis=1)
0 [nan, nan, nan, nan]
1 [1.0, nan, nan, nan]
2 [1.4142135623730951, 1.0, nan, nan]
3 [1.0, 1.0, 1.4142135623730951, nan]
4 [2.23606797749979, 2.0, 1.4142135623730951, 1.0]
5 [1828.4969237053695, 1826.2623031755325, 1826....
6 [1.0, 1829.3747565766835, 1827.1401150431786, ...
7 [1.0, 2.0, 1830.2527147910475, 1828.018052427273]
8 [1.0, 2.0, 3.0, 1831.1307981681703]
9 [2568.3321436294023, 2567.592062614309, 2566.8...
综合起来:
out = df.assign(
distances=pd.DataFrame(
vfun(list(range(1, k+1)), df[['x_cord', 'y_cord']].values).T,
index=df.index,
).apply(list, axis=1)
)
输出:
x_cord y_cord value \
3384209 1650 1741 0.009752
3382265 1650 1740 0.009481
3384208 1649 1741 0.008943
3382264 1649 1740 0.008676
3384210 1651 1741 0.008473
1679661 46 865 0.000000
1679660 45 865 0.000000
1679659 44 865 0.000000
1679658 43 865 0.000000
5038847 1944 2592 0.000000
distances
3384209 [nan, nan, nan, nan]
3382265 [1.0, nan, nan, nan]
3384208 [1.4142135623730951, 1.0, nan, nan]
3382264 [1.0, 1.0, 1.4142135623730951, nan]
3384210 [2.23606797749979, 2.0, 1.4142135623730951, 1.0]
1679661 [1828.4969237053695, 1826.2623031755325, 1826....
1679660 [1.0, 1829.3747565766835, 1827.1401150431786, ...
1679659 [1.0, 2.0, 1830.2527147910475, 1828.018052427273]
1679658 [1.0, 2.0, 3.0, 1831.1307981681703]
5038847 [2568.3321436294023, 2567.592062614309, 2566.8...
对于您的情况,设置 k=10
而不是 4。
我有一个已排序的(在 'values' 上)数据框,如下所示。未命名的列是索引。
x_cord y_cord value
3384209 1650 1741 0.009752
3382265 1650 1740 0.009481
3384208 1649 1741 0.008943
3382264 1649 1740 0.008676
3384210 1651 1741 0.008473
... ... ... ...
1679661 46 865 0.000000
1679660 45 865 0.000000
1679659 44 865 0.000000
1679658 43 865 0.000000
5038847 1944 2592 0.000000
如何创建另一个列,其中包含到前 n 行的欧氏距离列表?例如
- 第一行将有一个空列表
- 第二行将列出第一行和第二行之间的距离(参见坐标),即 1 项。
- 第三排会有。两个项目的列表,即第三个和第二个之间 以及第三和第一。
- 第 21 行将包含十个项目的列表,其自身与前九个点之间的欧氏距离。
该列表始终最多包含十(或 n)个元素。
我怎样才能做到这一点?
仅供参考
def euc_distance(x1, y1, x2, y2):
return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
首先,移动所有前 10 行,在每个移动的专用列中:
for i in range(1,11):
df["x_cord_"+str(i)] = df["x_cord"].shift(i)
df["y_cord_"+str(i)] = df["y_cord"].shift(i)
然后,计算每一行与现在存储在其专用列中的其他 10 个坐标之间的距离。 if
确保如果列中有 Nan
,则结果列表将不包含此值。
df["distance"] = df.apply(lambda row: [euc_distance(row["x_cord"], row["y_cord"], row["x_cord_"+str(i)], row["y_cord_"+str(i)]) for i in range(1,11) if not math.isnan(row["x_cord_"+str(i)])], axis=1)
最后,删除仅为计算创建的列。
df = df[["x_cord", "y_cord", "value", "distance"]]
输出:
x_cord y_cord value distance
3384209 1650 1741 0.009752 []
3382265 1650 1740 0.009481 [1.0]
3384208 1649 1741 0.008943 [1.4142135623730951, 1.0]
3382264 1649 1740 0.008676 [1.0, 1.0, 1.4142135623730951]
3384210 1651 1741 0.008473 [2.23606797749979, 2.0, 1.4142135623730951, 1.0]
可能还可以改进。
Numpy 助你一臂之力! (快速 解决方案,主要是矢量化):
def fun(k, z):
na = np.full((k, z.shape[1]), np.nan)
a = np.row_stack((na, z[:-k, :]))
return np.linalg.norm(z - a, axis=1)
vfun = np.vectorize(fun, signature='(),(n,m)->(n)')
现在,您可以获得包含所有距离的数组 (n, k)
:
>>> k = 4 # just for nice printing; replace with 10 in your setting
>>> z = pd.DataFrame(vfun(range(1, k+1), df[['x_cord', 'y_cord']].values).T)
... z
0 1 2 3
0 NaN NaN NaN NaN
1 1.000000 NaN NaN NaN
2 1.414214 1.000000 NaN NaN
3 1.000000 1.000000 1.414214 NaN
4 2.236068 2.000000 1.414214 1.000000
5 1828.496924 1826.262303 1826.741635 1827.140115
6 1.000000 1829.374757 1827.140115 1827.619216
7 1.000000 2.000000 1830.252715 1828.018052
8 1.000000 2.000000 3.000000 1831.130798
9 2568.332144 2567.592063 2566.852158 2566.112429
如果您愿意,可以将其转换为列表:
>>> z.apply(list, axis=1)
0 [nan, nan, nan, nan]
1 [1.0, nan, nan, nan]
2 [1.4142135623730951, 1.0, nan, nan]
3 [1.0, 1.0, 1.4142135623730951, nan]
4 [2.23606797749979, 2.0, 1.4142135623730951, 1.0]
5 [1828.4969237053695, 1826.2623031755325, 1826....
6 [1.0, 1829.3747565766835, 1827.1401150431786, ...
7 [1.0, 2.0, 1830.2527147910475, 1828.018052427273]
8 [1.0, 2.0, 3.0, 1831.1307981681703]
9 [2568.3321436294023, 2567.592062614309, 2566.8...
综合起来:
out = df.assign(
distances=pd.DataFrame(
vfun(list(range(1, k+1)), df[['x_cord', 'y_cord']].values).T,
index=df.index,
).apply(list, axis=1)
)
输出:
x_cord y_cord value \
3384209 1650 1741 0.009752
3382265 1650 1740 0.009481
3384208 1649 1741 0.008943
3382264 1649 1740 0.008676
3384210 1651 1741 0.008473
1679661 46 865 0.000000
1679660 45 865 0.000000
1679659 44 865 0.000000
1679658 43 865 0.000000
5038847 1944 2592 0.000000
distances
3384209 [nan, nan, nan, nan]
3382265 [1.0, nan, nan, nan]
3384208 [1.4142135623730951, 1.0, nan, nan]
3382264 [1.0, 1.0, 1.4142135623730951, nan]
3384210 [2.23606797749979, 2.0, 1.4142135623730951, 1.0]
1679661 [1828.4969237053695, 1826.2623031755325, 1826....
1679660 [1.0, 1829.3747565766835, 1827.1401150431786, ...
1679659 [1.0, 2.0, 1830.2527147910475, 1828.018052427273]
1679658 [1.0, 2.0, 3.0, 1831.1307981681703]
5038847 [2568.3321436294023, 2567.592062614309, 2566.8...
对于您的情况,设置 k=10
而不是 4。