Проверьте, есть ли точки в 3D окне по координатам в пандах - PullRequest
1 голос
/ 27 сентября 2019

У меня есть координаты 3D-блока (ориентированного по той же ссылке и с координатами min и max по XYZ) в кадре данных BOX И координаты XYZ точек в кадре данных PTS

BOX = pd.DataFrame({'Box':['BA', 'BB', 'BC'], 'Box-Xmin':[1, 2, 30], 'Box-Ymin':[1,2,30], 'Box-Zmin':[1,2,30], 'Box-Xmax':[2,4,60], 'Box-Ymax':[2,4,60], 'Box-Zmax':[2,4,60]})
PTS = pd.DataFrame({'Point':['P1', 'P2', 'P3'], 'Pt-X':[0, 45, 20], 'Pt-Y':[8,33,40], 'Pt-Z':[5,30,50]})

Я пытаюсьсделайте слияние, объедините оба этих кадра данных, когда точка находится в поле, как:

Box Point
BA 
BB 
BC  P2
BC  P3

У меня есть проверка на стороне геопанд, но это больше для 2D координат.

Спасибо :)

Ответы [ 2 ]

2 голосов
/ 27 сентября 2019

Если ваши данные не слишком велики, вы можете использовать широковещательную рассылку:

# for convenience
bmins = BOX.filter(like='min').values
bmaxs = BOX.filter(like='max').values
coords = PTS.filter(like='Pt').values

xy = np.nonzero(((coords[:,None, :] >= bmins) &  # compare each coordinate with min
                 (coords[:,None, :] <= bmaxs)    # compare each coordinate with max
                ).all(-1)                       # make sure all comparisons are True
               )                                # nonzero collects only True values

new_df = pd.DataFrame({'Box':BOX.loc[xy[1],'Box'].values,
                       'Point':PTS.loc[xy[0],'Point'].values})

Выход:

  Box Point
0  BC    P2
1  BC    P3

, который вы можете объединить в BOX для желаемого выхода, например:

BOX[['Box']].merge(new_df, on='Box', how='left')

дает:

  Box Point
0  BA   NaN
1  BB   NaN
2  BC    P2
3  BC    P3
1 голос
/ 27 сентября 2019

вы также можете сделать это с NumPy, как показано ниже, не уверен, что он работает лучше, но я думаю, что это должно

BOX = pd.DataFrame({'Box':['BA', 'BB', 'BC'], 'Box-Xmin':[1, 2, 30], 'Box-Ymin':[1,2,30], 'Box-Zmin':[1,2,30], 'Box-Xmax':[50,4,60], 'Box-Ymax':[50,4,60], 'Box-Zmax':[50,4,60]})
PTS = pd.DataFrame({'Point':['P1', 'P2', 'P3'], 'Pt-X':[7, 45, 40], 'Pt-Y':[8,33,40], 'Pt-Z':[5,30,60]})


l_box = BOX[["Box-Xmin","Box-Ymin","Box-Zmin"]].values
u_box = BOX[["Box-Xmax","Box-Ymax","Box-Zmax"]].values

## add new dimension to use broadcast to compare all pairs of box and points
pts = PTS[["Pt-X","Pt-Y","Pt-Z"]].values[:, np.newaxis, :]

# this is convenient expression but the block below will use less memory
# cond = np.all((l_box<= pts) & (pts<=u_box), axis=2)

cond1 = np.greater_equal(pts, l_box)
cond2 = np.greater_equal(u_box, pts)
np.logical_and(cond1, cond2, out=cond1)
cond2 = None
cond = np.all(cond1, axis=2)

# fancy index for points falling inside box
pts_ind = np.arange(len(pts)).reshape(-1,1).repeat(np.sum(cond, axis=1))

# fancy index of box having points
box_ind = np.arange(len(l_box)).repeat(np.sum(cond, axis=0))

# finally create dataframe using the numpy array
pd.DataFrame(dict(Box=BOX["Box"].values[box_ind], 
Point=PTS["Point"].values[pts_ind]))

Результат

**Input**
Box Box-Xmin    Box-Ymin    Box-Zmin    Box-Xmax    Box-Ymax    Box-Zmax
0   BA  1   1   1   50  50  50
1   BB  2   2   2   4   4   4
2   BC  30  30  30  60  60  60


Point   Pt-X    Pt-Y    Pt-Z
0   P1  7   8   5
1   P2  45  33  30
2   P3  40  40  60

**Result**
    Box Point
0   BA  P1
1   BA  P2
2   BC  P2
3   BC  P3

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...