选择行和应用功能的更快方法

时间:2019-12-10 05:28:41

标签: python pandas numpy dataframe itertools

我希望在以下数据中计算当前点与下一个终点之间的距离。单个键可以具有多个端点(x,y)。

我正在寻求比上述解决方案更快的解决方案,因为执行该过程需要花费大量时间。

check the formula for calculate distance bewteen 2 endpoints

数据

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);
   });

我尝试过的事情:

解决方案1 ​​


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

行很多,执行上述代码要花费几个小时。

解决方案2(无效)

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))

2 个答案:

答案 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