我希望在以下数据中计算当前点与下一个终点之间的距离。单个键可以具有多个端点(x,y)。
我正在寻求比上述解决方案更快的解决方案,因为执行该过程需要花费大量时间。
let username = 'Secret_ID';
let password = 'Secret_Key';
let formdata = new FormData();
let headers = new Headers();
formdata.append('Content-Type','application/x-www-form-urlencoded');
formdata.append('grant_type','password');
formdata.append('username','mahesh@gmail.com');
formdata.append('password','Welcome1234');
formdata.append('scope','https://si01-test.prod.com/bca/api');
headers.append('Authorization', 'Basic VGVzdF9zaTAxX0FQUElEOjNkZGI4MmYxLWI5OTktNDlhMy1hMmM5LWQ1OGMyOTU2ODg4Yg=='); // encoded username and password
fetch('https://identity.com/oauth2/v1/token', {
method: 'POST',
headers: headers,
body: formdata
}).then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson
})
})
.catch((error) => {
console.error(error);
});
Key x y
1 87.4375 28.921875
1 97.4375 23.921875
1 97.4375 23.921875
1 97.4375 23.921875
1 97.4375 23.921875
2 86.4375 24.921875
2 85.4375 24.921875
2 93.4375 29.921875
2 86.4375 24.921875
2 85.4375 24.921875
2 93.4375 29.921875
行很多,执行上述代码要花费几个小时。
new_df= pd.DataFrame(columns=['key', 'distance'])
for key in orig_df.key.values:
x2 = orig_df.loc[orig_df.key== key ,'x'].shift(-1)
y2 = orig_df.loc[orig_df.key== key ,'y'].shift(-1)
x1 = orig_df.loc[orig_df.key== key ,'x']
y1 = orig_df.loc[orig_df.key== key ,'y']
distance = cal_distance(x2,y2,x1,y1)
new_df.append({'key': key, 'distance': distance}, ignore_index=True)
def cal_distance(x2,y2,x1,y1):
return abs(np.sqrt( np.square(x2 - x1) + np.square(y2 - y1))).sum()
我试图根据密钥进行分组。
非常感谢任何帮助。
orig_df.groupby('key').pipe(cal_distance(orig_df.x.shift(-1),orig_df.y.shift(-1),orig_df.x,orig_df.y))
答案 0 :(得分:2)
# Random data (1m rows, 1000 keys)
np.random.seed(0)
rows = 1_000_000
keys = 1000
keys = np.random.randint(low=1, high=keys, size=rows)
x = np.random.rand(rows) * 360
y = np.random.rand(rows) * 360
df = pd.DataFrame({'key': keys, 'x': x, 'y': y})
解决方案
这将计算每个基于键的组中后续点之间的距离,然后汇总每个键的总距离。根据上面具有100万行的样本数据,这大约需要0.8秒。
df.sort_values('key', kind='mergesort', inplace=True) # `mergesort` is the only stable algorithm.
distances = (
df
.apply(lambda s: s.diff().pow(2)).sum(axis=1).pow(0.5) # Calculate distances b/w endpoints.
.groupby(df['key'])
.apply(lambda s: s.iloc[1:].sum()) # Sum the distances between endpoints by key.
)
>>> distances.head()
key
1 198431.901333
2 192694.829351
3 176125.208567
4 186942.057497
5 182029.077809
dtype: float64
预期输出 使用OP的原始数据框,以上解决方案将产生预期的输出:
>>> distances
key
1 11.180340
2 29.470288
dtype: float64
对代码的评论
在解决方案1 中查看代码,您正在遍历_all_the键值(for key in orig_df.key.values:
)。那将是上面的示例数据中的11个循环。对于每个循环,然后使用.loc
查找该键的值。请注意,每个.loc
操作都基于键而不是行返回相同的 group 。
假设key=2
,您的数据如下所示:
x1 x2 y1 y2
5 86.4375 85.4375 24.921875 24.921875
6 85.4375 93.4375 24.921875 29.921875
7 93.4375 86.4375 29.921875 24.921875
8 86.4375 85.4375 24.921875 24.921875
9 85.4375 93.4375 24.921875 29.921875
10 93.4375 NaN 29.921875 NaN
所以np.sqrt( np.square(x1 - x2) + np.square(y1 - y2))
的输出是这样的:
5 1.000000
6 9.433981
7 8.602325
8 1.000000
9 9.433981
10 NaN
dtype: float64
您然后错误地在何处对列求和。您需要对指定轴(.sum(axis=1)
的每一行求和。此外,我不确定您的移位方向是否正确,但这取决于原始数据的结构。最后,可能不会无关紧要,但这取决于您打算如何使用结果。
作为次要点,您不需要在函数中取绝对值,因为两个平方值的总和始终为非负数,因此总和的平方根也是如此。
答案 1 :(得分:2)
编辑:正如预期的那样,实际期望的行为与我所猜测的略有不同。我将更新我的答案以反映这一点,这应该是一个小调整。
从哪里开始。您的代码非常简单。我敢肯定,惯用的Pandas代码不会花费数小时就能产生结果。甚至不清楚为什么首先要使用Pandas。正如您将在以下我的解决方案中看到的那样,使用Pandas会使事情变得比原本应该的更加笨拙和笨拙。
当然,这可能不是理想的结果,因为问题是模棱两可且不清楚的。
from io import StringIO
import numpy as np
import pandas as pd
raw_str = \
'''
key x y
1 87.4375 28.921875
1 97.4375 23.921875
1 97.4375 23.921875
1 97.4375 23.921875
1 97.4375 23.921875
2 86.4375 24.921875
2 85.4375 24.921875
2 93.4375 29.921875
2 86.4375 24.921875
2 85.4375 24.921875
2 93.4375 29.921875
'''
df = pd.read_csv(StringIO(raw_str), delim_whitespace=True)
rows_list = []
for k, v in df.groupby('key'):
coords = v[['x', 'y']].to_numpy()
coords_shifted = np.roll(coords, shift=-1, axis=0)
dist = np.linalg.norm(coords[:-1] - coords_shifted[:-1], axis=1).sum()
rows_list.append((k, dist))
res_df = pd.DataFrame(data=rows_list, columns=['key', 'distance'])
print(res_df)
res_df
:
key distance
0 1 11.180340
1 2 29.470288