#python #pandas #dataframe #filter
#python #pandas #фрейм данных #Фильтр
Вопрос:
Проект, над которым я работаю, требует объединения двух фреймов данных вместе вдоль некоторой линии с дельтой. В принципе, мне нужно взять фрейм данных с нелинейной 2D-линией и найти точки данных внутри другого, которые попадают вдоль этой линии, плюс или минус дельта.
Фрейм данных 1 (строка, вдоль которой мы хотим найти точки)
import pandas as pd
df1 = pd.read_csv('path/to/df1/data.csv')
df1
x y
0 0.23 0.54
1 0.27 0.95
2 0.78 1.59
...
97 0.12 2.66
98 1.74 0.43
99 0.93 4.23
Фрейм данных 2 (Фрейм данных, который мы хотим отфильтровать, оставляя точки в пределах некоторой дельты)
df2 = pd.read_csv('path/to/df2/data.csv')
df2
x y
0 0.21 0.51
1 0.27 0.35
2 3.45 1.19
...
971 0.94 2.60
982 1.01 1.33
993 0.43 2.43
Нахождение грубой линии
DELTA = 0.03
coarse_line = find_coarse_line(df1, df2, DELTA)
coarse_line
x y
0 0.21 0.51
1 0.09 2.68
2 0.23 0.49
...
345 1.71 0.45
346 0.96 0.40
347 0.81 1.62
Я пробовал использовать df.loc((df['x'] >= BOTLEFT_X) amp; (df['x'] >= BOTLEFT_Y) amp; (df['x'] <= TOPRIGHT_X) amp; (df['y'] <= TOPRIGHT_Y))
среди многих, многих других функций Pandas и еще много чего, но пока не нашел ничего, что работало бы, а тем более чего-либо эффективного (с наборами данных> 2 миллионов точек).
Комментарии:
1. Можете ли вы предоставить пригодные для использования образцы данных?
head()
из двух фреймов данных, где есть пересечения. Обычный подход к работе с непрерывными данными, когда вы хотите сопоставить их, заключается в том, чтобы поместить их в ячейкиpd.cut()
Ответ №1:
Применили подход, основанный на использовании, merge()
где x, y были помещены в ячейки из хорошей кривой df1
- сгенерирована однородная линия, y = x ^ 2
- произвел рандомизацию небольшого количества для генерации
df1
- произвел рандомизацию большого количества для генерации
df2
также сгенерировал в три раза больше координат - возьмите
df1
в качестве эталона подходящие диапазоны координат x и y для разделения на ячейки, используяpd.cut()
. ячейки, составляющие 1/3 от общего числа координат, работают хорошо - стандартизировал их обратно в массивы для повторного использования в
pd.cut()
при объединении
Как видно из точечных графиков, он выполняет довольно разумную работу по поиску и удержанию точек близко к кривой в df2
import pandas as pd
import random
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1,3, sharey=True, sharex=False, figsize=[20,5])
linex = [i for i in range(100)]
liney = [i**2 for i in linex]
df1 = pd.DataFrame({"x":[l*random.uniform(0.95, 1.05) for l in linex],
"y":[l*random.uniform(0.95, 1.05) for l in liney]})
df1.plot("x","y", kind="scatter", ax=ax[0])
df2 = pd.DataFrame({"x":[l*random.uniform(0.5, 1.5) for l in linex*3],
"y":[l*random.uniform(0.5, 1.5) for l in liney*3]})
df2.plot("x","y", kind="scatter", ax=ax[1])
# use bins on x and y axis - both need to be within range to find
bincount = len(df1)//3
xc = pd.cut(df1["x"], bincount).unique()
yc = pd.cut(df1["y"], bincount).unique()
xc = np.sort([intv.left for intv in xc] [xc[-1].right])
yc = np.sort([intv.left for intv in yc] [yc[-1].right])
dfm = (df2.assign(
xb=pd.cut(df2["x"],xc, duplicates="drop"),
yb=pd.cut(df2["y"],yc, duplicates="drop"),
).query("~(xb.isna() | yb.isna())") # exclude rows where df2 falls outside of range of df1
.merge(df1.assign(
xb=pd.cut(df1["x"],xc, duplicates="drop"),
yb=pd.cut(df1["y"],yc, duplicates="drop"),
),
on=["xb","yb"],
how="inner",
suffixes=("_l","_r")
)
)
dfm.plot("x_l", "y_l", kind="scatter", ax=ax[2])
print(f"graph 2 pairs:{len(df2)} graph 3 pairs:{len(dfm)}")