ส่งกลับระยะทางไปยังจุดที่ใกล้ที่สุดโดยกลุ่ม - python

ฉันหวังว่าจะคำนวณระยะทางไปยังจุดที่ใกล้ที่สุดโดยจัดกลุ่มตามรายการเฉพาะ โดยเฉพาะการใช้ด้านล่างนี้ calculate_distances จะวัดระยะทางระหว่าง id แต่ละรายการกับจุดที่เหลือ ฉันหวังว่าจะคืนระยะทางไปยังจุดที่ใกล้ที่สุด แต่สำหรับแต่ละรายการใน Group ดังนั้นระยะทางที่ใกล้ที่สุดถึง Red และระยะทางที่ใกล้ที่สุดถึง Grn

หมายเหตุ: ฉันมี 3 รายการที่ไม่ซ้ำกันในแต่ละ Group ฉันหวังว่าจะจัดการกับสินค้าที่ไม่ซ้ำหลายรายการซึ่งมีป้ายกำกับที่แตกต่างกัน

import pandas as pd
import numpy as np
from scipy.spatial.distance import pdist, squareform

df = pd.DataFrame({              
    'Time' : [1,1,1,1,1,1,2,2,2,2,2,2],             
    'ID' : ['A','B','C','X','U','V','A','B','C','X','U','V'],      
    'Group' : ['Red','Red','Red','Grn','Grn','Grn','Red','Red','Red','Grn','Grn','Grn'],           
    'X' : [2.0,3.0,4.0,2.0,2.0,1.0,1.0,6.0,4.0,2.0,5.0,3.0],
    'Y' : [3.0,1.0,0.0,0.0,2.0,1.0,2.0,0.0,1.0,1.0,0.0,0.0],           
    })

def calculate_distances(df):

    id_distances = pd.DataFrame(
        squareform(pdist(df[['X', 'Y']].to_numpy())),  
        columns = df['ID'],
        index = df['ID'],
    )

    return id_distances

df_distances = df.groupby(['Time']).apply(calculate_distances).reset_index()

เอาท์พุทที่ตั้งใจไว้:

ID  Time ID  dist_Red  dist_Grn                                    
0      1  A  2.236068  1.000000  
1      1  B  1.414214  1.414214  
2      1  C  1.414214  2.000000  
3      1  X  1.414214  2.000000  
4      1  U  1.000000  1.414214  
5      1  V  2.236068  1.414214  
6      2  A  3.162278  1.414214  
7      2  B  2.236068  1.000000  
8      2  C  2.236068  1.414214 
9      2  X  1.414214  1.414214
10     2  U  1.000000  2.000000
11     2  V  1.414214  1.414214

person jonboy    schedule 14.12.2020    source แหล่งที่มา


คำตอบ (1)


ฉันไม่พบวิธีตรงไปตรงมาที่ดี เนื่องจากจากตัวอย่างของคุณดูเหมือนว่าคุณไม่ต้องการรวมประเด็นนั้นไว้ ฉันลงเอยด้วยการสร้างกลุ่มและคำนวณระยะทางภายในกลุ่มเหล่านั้น

แก้ไข: เพิ่มรูปแบบที่ (ควร) รวม ID ของจุดที่ใกล้ที่สุด

from sklearn.neighbors import BallTree
import pandas as pd
import numpy as np
from scipy.spatial.distance import pdist, squareform

df = pd.DataFrame({              
    'Time' : [1,1,1,1,1,1,2,2,2,2,2,2],             
    'ID' : ['A','B','C','X','U','V','A','B','C','X','U','V'],      
    'Group' : ['Red','Red','Red','Grn','Grn','Grn','Red','Red','Red','Grn','Grn','Grn'],           
    'X' : [2.0,3.0,4.0,2.0,2.0,1.0,1.0,6.0,4.0,2.0,5.0,3.0],
    'Y' : [3.0,1.0,0.0,0.0,2.0,1.0,2.0,0.0,1.0,1.0,0.0,0.0],           
    })


def subgroup_distance(df, group_column='Group', include_point_itself=True):    
    groups = df[group_column].unique()

    all_points = df[['X','Y']].values
    
    for group in groups:
        group_points = df[df[group_column] == group][['X','Y']]
        tree = BallTree(group_points, leaf_size=15, metric='minkowski')
        
        if include_point_itself:
            distance, index = tree.query(all_points, k=1)
            distances = distance[:,0]
            distance_column_name = "distance_{}".format( group )
            df[ distance_column_name ] = distances
                
        else:
            indici = (df[group_column] == group).values * 1
            distance, index = tree.query(all_points, k=2)
            distances = distance[ np.arange(distance.shape[0]), indici]

            distance_column_name = "distance_{}".format( group )
            df[ distance_column_name ] = distances

    return df

def calculate_distances(df):
    return subgroup_distance(df, include_point_itself=False)

df_distances = df.groupby(['Time']).apply(calculate_distances).reset_index()

สิ่งนี้จะส่งออก

    index  Time ID Group    X    Y  distance_Red  distance_Grn
0       0     1  A   Red  2.0  3.0      2.236068      1.000000
1       1     1  B   Red  3.0  1.0      1.414214      1.414214
2       2     1  C   Red  4.0  0.0      1.414214      2.000000
3       3     1  X   Grn  2.0  0.0      1.414214      1.414214
4       4     1  U   Grn  2.0  2.0      1.000000      1.414214
5       5     1  V   Grn  1.0  1.0      2.000000      1.414214
6       6     2  A   Red  1.0  2.0      3.162278      1.414214
7       7     2  B   Red  6.0  0.0      2.236068      1.000000
8       8     2  C   Red  4.0  1.0      2.236068      1.414214
9       9     2  X   Grn  2.0  1.0      1.414214      1.414214
10     10     2  U   Grn  5.0  0.0      1.000000      2.000000
11     11     2  V   Grn  3.0  0.0      1.414214      1.414214

รูปแบบที่จะส่งออก ID ของจุดที่ใกล้ที่สุดในกลุ่มย่อย

def subgroup_distance_with_nearest(df, group_column='Group', include_point_itself=True):    
    groups = df[group_column].unique()

    all_points = df[['X','Y']].values
    
    for group in groups:
        group_points = df[df[group_column] == group][['X','Y']]
        tree = BallTree(group_points, leaf_size=15, metric='minkowski')
        
        distances = None
        nearest_id = None
        
        if include_point_itself:
            distance, index = tree.query(all_points, k=1)
            distances = distance[:,0]
            nearest_id = group_points.index[index[:,0]]
                        
        else:
            indici = (df[group_column] == group).values * 1
            distance, index = tree.query(all_points, k=2)
            distances = distance[ np.arange(distance.shape[0]), indici]
            index_indici =  index[ np.arange(distance.shape[0]), indici]
            nearest_id = group_points.index[index_indici]

        distance_column_nearest_name = "nearest_index_{}".format( group )
        distance_column_name = "distance_{}".format( group )
        df[ distance_column_name ] = distances
        df[ distance_column_nearest_name] = nearest_id


    return df

def subgroup_distance_with_nearest(df):
    return subgroup_distance(df, include_point_itself=False)

df_distances = df.groupby(['Time']).apply(calculate_distances).reset_index()

และมันจะส่งออก

    index  Time ID Group    X    Y  distance_Red  nearest_index_Red  \
0       0     1  A   Red  2.0  3.0      2.236068                  1   
1       1     1  B   Red  3.0  1.0      1.414214                  2   
2       2     1  C   Red  4.0  0.0      1.414214                  1   
3       3     1  X   Grn  2.0  0.0      1.414214                  1   
4       4     1  U   Grn  2.0  2.0      1.000000                  0   
5       5     1  V   Grn  1.0  1.0      2.000000                  1   
6       6     2  A   Red  1.0  2.0      3.162278                  8   
7       7     2  B   Red  6.0  0.0      2.236068                  8   
8       8     2  C   Red  4.0  1.0      2.236068                  7   
9       9     2  X   Grn  2.0  1.0      1.414214                  6   
10     10     2  U   Grn  5.0  0.0      1.000000                  7   
11     11     2  V   Grn  3.0  0.0      1.414214                  8   

    distance_Grn  nearest_index_Grn  
0       1.000000                  4  
1       1.414214                  4  
2       2.000000                  3  
3       1.414214                  5  
4       1.414214                  5  
5       1.414214                  3  
6       1.414214                  9  
7       1.000000                 10  
8       1.414214                 11  
9       1.414214                 11  
10      2.000000                 11  
11      1.414214                  9  

ฉันไม่ได้คำนวณใหม่และทดสอบ ID แต่อย่างน้อยก็ดูเหมือนว่าจะถูกต้องที่ส่งคืน ID จากกลุ่มย่อย

person Willem Hendriks    schedule 14.12.2020
comment
ขอบคุณ. ไม่จำเป็นต้องใส่ประเด็นลงไปแต่สิ่งนี้จะจัดการทุกอย่าง ดี - person jonboy; 15.12.2020
comment
มีวิธีคืนป้ายกำกับ ID ด้วยหรือไม่ - person jonboy; 15.12.2020
comment
แค่คอลัมน์ ID เหมือนเดิมเหรอ? - person Willem Hendriks; 15.12.2020
comment
ขอโทษ. วัดระยะทางสัมพัทธ์ที่ใกล้ที่สุดสำหรับ Group แต่ละตัว แต่เราไม่รู้ว่ามันคือ ID อันไหน ดังนั้นเมื่อพิจารณาดัชนี 0 หรือ A ค่าที่ใกล้เคียงที่สุด ID คือ B สำหรับ Red และ U สำหรับ Grn - person jonboy; 15.12.2020
comment
ฉันเข้าใจแล้ว โชคดีที่ sklearn ส่งคืนพวกมันเช่นกัน ดังนั้นการเล่นกลดัชนีเล็กน้อยก็จะส่งคืนพวกมัน หากการเล่นกลดัชนีของฉันเป็นไปด้วยดี ก็ควรคืนดัชนีเหล่านั้นทันที - person Willem Hendriks; 15.12.2020
comment
ขอบคุณมาก ๆ! - person jonboy; 16.12.2020