mempercepat pemeriksaan berurutan apakah suatu titik berbentuk dengan Python

Saya memiliki kode secara berurutan apakah setiap pasangan koordinat kartesius yang ditemukan di DataFrame saya termasuk dalam area tertutup geometris tertentu. Tapi ini agak lambat, saya kira karena tidak di-vektorisasi. Berikut ini contohnya:

from matplotlib.patches import Rectangle

r1 = Rectangle((0,0), 10, 10)
r2 = Rectangle((50,50), 10, 10)

df = pd.DataFrame([[1,2],[-1,5], [51,52]], columns=['x', 'y'])

for j in range(df.shape[0]):
    coordinates = df.x.iloc[j], df.y.iloc[j]
    if r1.contains_point(coordinates):
        df['location'].iloc[j] = 0
    else r2.contains_point(coordinates):
        df['location'].iloc[j] = 1

Adakah yang bisa mengusulkan pendekatan untuk mempercepat?


person splinter    schedule 22.03.2017    source sumber


Jawaban (1)


Lebih baik mengubah tambalan persegi panjang menjadi sebuah array dan mengerjakannya setelah menyimpulkan sejauh mana penyebarannya.

def seqcheck_vect(df):
    xy = df[["x", "y"]].values
    e1 = np.asarray(rec1.get_extents())
    e2 = np.asarray(rec2.get_extents())
    r1m1, r1m2 = np.min(e1), np.max(e1)
    r2m1, r2m2 = np.min(e2), np.max(e2)
    out = np.where(((xy >= r1m1) & (xy <= r1m2)).all(axis=1), 0, 
                   np.where(((xy >= r2m1) & (xy <= r2m2)).all(axis=1), 1, np.nan))
    return df.assign(location=out)

Untuk sampel yang diberikan, output fungsi:

masukkan deskripsi gambar di sini


tolok ukur:

def loopy_version(df):
    for j in range(df.shape[0]):
        coordinates = df.x.iloc[j], df.y.iloc[j]
        if rec1.contains_point(coordinates):
            df.loc[j, "location"] = 0
        elif rec2.contains_point(coordinates):
            df.loc[j, "location"] = 1
        else:
            pass
    return df

menguji pada DF dari 10 ribu baris:

np.random.seed(42)
df  = pd.DataFrame(np.random.randint(0, 100, (10000,2)), columns=list("xy"))

# check if both give same outcome
loopy_version(df).equals(seqcheck_vect(df))
True

%timeit loopy_version(df)
1 loop, best of 3: 3.8 s per loop

%timeit seqcheck_vect(df)
1000 loops, best of 3: 1.73 ms per loop

Jadi, pendekatan vektorisasi kira-kira 2200 kali lebih cepat dibandingkan pendekatan gila.

person Nickil Maveli    schedule 22.03.2017
comment
Terima kasih. Namun saya bertanya-tanya, apakah ada metode yang lebih umum yang tidak mengandalkan persegi panjang, tetapi di-vektor-kan? Pendekatan Anda memang mengandalkannya jika saya tidak salah - person splinter; 22.03.2017
comment
Pada dasarnya struktur apa pun yang memiliki rentang untuk dibandingkan dengan nilai yang ada di DF akan mengikuti implementasi serupa seperti yang ditunjukkan di atas. Harus ada cara di mana Anda dapat mengekstrak titik awal dan akhir dari titik tersebut dan menyimpan hasilnya dalam sebuah array. - person Nickil Maveli; 22.03.2017
comment
Selain itu, semua tambalan memiliki metode .get_extents(), jadi saya kira itu tidak akan menimbulkan masalah. - person Nickil Maveli; 22.03.2017