Saya bekerja dengan pointcloud 3D dari Lidar. Poin diberikan oleh array numpy yang terlihat seperti ini:
points = np.array([[61651921, 416326074, 39805], [61605255, 416360555, 41124], [61664810, 416313743, 39900], [61664837, 416313749, 39910], [61674456, 416316663, 39503], [61651933, 416326074, 39802], [61679969, 416318049, 39500], [61674494, 416316677, 39508], [61651908, 416326079, 39800], [61651908, 416326087, 39802], [61664845, 416313738, 39913], [61674480, 416316668, 39503], [61679996, 416318047, 39510], [61605290, 416360572, 41118], [61605270, 416360565, 41122], [61683939, 416313004, 41052], [61683936, 416313033, 41060], [61679976, 416318044, 39509], [61605279, 416360555, 41109], [61664837, 416313739, 39915], [61674487, 416316666, 39505], [61679961, 416318035, 39503], [61683943, 416313004, 41054], [61683930, 416313042, 41059]])
Saya ingin menjaga data saya dikelompokkan ke dalam ukuran kubus 50*50*50
sehingga setiap kubus mempertahankan beberapa indeks hashable dan indeks numpy dari points
isinya . Untuk mendapatkan pemisahan, saya menetapkan cubes = points \\ 50
output mana ke:
cubes = np.array([[1233038, 8326521, 796], [1232105, 8327211, 822], [1233296, 8326274, 798], [1233296, 8326274, 798], [1233489, 8326333, 790], [1233038, 8326521, 796], [1233599, 8326360, 790], [1233489, 8326333, 790], [1233038, 8326521, 796], [1233038, 8326521, 796], [1233296, 8326274, 798], [1233489, 8326333, 790], [1233599, 8326360, 790], [1232105, 8327211, 822], [1232105, 8327211, 822], [1233678, 8326260, 821], [1233678, 8326260, 821], [1233599, 8326360, 790], [1232105, 8327211, 822], [1233296, 8326274, 798], [1233489, 8326333, 790], [1233599, 8326360, 790], [1233678, 8326260, 821], [1233678, 8326260, 821]])
Output yang saya inginkan terlihat seperti ini:
{(1232105, 8327211, 822): [1, 13, 14, 18]),
(1233038, 8326521, 796): [0, 5, 8, 9],
(1233296, 8326274, 798): [2, 3, 10, 19],
(1233489, 8326333, 790): [4, 7, 11, 20],
(1233599, 8326360, 790): [6, 12, 17, 21],
(1233678, 8326260, 821): [15, 16, 22, 23]}
Pointcloud saya yang sebenarnya berisi beberapa ratus juta poin 3D. Apa cara tercepat untuk melakukan pengelompokan semacam ini?
Saya sudah mencoba mayoritas dari berbagai solusi. Berikut adalah perbandingan perhitungan waktu dengan asumsi ukuran poin adalah sekitar 20 juta dan ukuran kubus berbeda adalah sekitar 1 juta:
Pandas [tuple (elem) -> np.array (dtype = int64)]
import pandas as pd
print(pd.DataFrame(cubes).groupby([0,1,2]).indices)
#takes 9sec
Defauldict [elem.tobytes () atau tuple -> list]
#thanks @abc:
result = defaultdict(list)
for idx, elem in enumerate(cubes):
result[elem.tobytes()].append(idx) # takes 20.5sec
# result[elem[0], elem[1], elem[2]].append(idx) #takes 27sec
# result[tuple(elem)].append(idx) # takes 50sec
numpy_indexed [int -> np.array]
# thanks @Eelco Hoogendoorn for his library
values = npi.group_by(cubes).split(np.arange(len(cubes)))
result = dict(enumerate(values))
# takes 9.8sec
Pengurangan panda + dimensi [int -> np.array (dtype = int64)]
# thanks @Divakar for showing numexpr library:
import numexpr as ne
def dimensionality_reduction(cubes):
#cubes = cubes - np.min(cubes, axis=0) #in case some coords are negative
cubes = cubes.astype(np.int64)
s0, s1 = cubes[:,0].max()+1, cubes[:,1].max()+1
d = {'s0':s0,'s1':s1,'c0':cubes[:,0],'c1':cubes[:,1],'c2':cubes[:,2]}
c1D = ne.evaluate('c0+c1*s0+c2*s0*s1',d)
return c1D
cubes = dimensionality_reduction(cubes)
result = pd.DataFrame(cubes).groupby([0]).indices
# takes 2.5 seconds
Anda dapat mengunduh cubes.npz
file di sini dan menggunakan perintah
cubes = np.load('cubes.npz')['array']
untuk memeriksa waktu kinerja.
numpy_indexed
hanya mendekatinya juga. Saya kira itu benar. Saya menggunakanpandas
untuk proses klasifikasi saya saat ini.Jawaban:
Jumlah konstan indeks per grup
Pendekatan # 1
Kita dapat melakukan
dimensionality-reduction
untuk mengurangicubes
ke array 1D. Ini didasarkan pada pemetaan data kubus yang diberikan ke grid n-dim untuk menghitung persamaan indeks linear, dibahas secara rincihere
. Kemudian, berdasarkan keunikan dari indeks linear tersebut, kita dapat memisahkan grup unik dan indeks terkaitnya. Oleh karena itu, mengikuti strategi-strategi itu, kita akan memiliki satu solusi, seperti -Alternatif # 1: Jika nilai integer
cubes
terlalu besar, kita mungkin ingin melakukandimensionality-reduction
sedemikian rupa sehingga dimensi dengan tingkat yang lebih pendek dipilih sebagai sumbu utama. Karenanya, untuk kasus-kasus tersebut, kita dapat memodifikasi langkah reduksi untuk mendapatkannyac1D
, seperti -Pendekatan # 2
Selanjutnya, kita dapat menggunakan
Cython-powered kd-tree
pencarian tetangga terdekat terdekat untuk mendapatkan indeks tetangga terdekat dan karenanya menyelesaikan kasus kita seperti ini -Kasus umum: Jumlah variabel indeks per grup
Kami akan memperluas metode berbasis argsort dengan beberapa pemisahan untuk mendapatkan hasil yang diinginkan, seperti -
Menggunakan versi 1D grup
cubes
sebagai kunciKami akan memperluas metode yang terdaftar sebelumnya dengan kelompok
cubes
sebagai kunci untuk menyederhanakan proses pembuatan kamus dan juga membuatnya efisien dengan itu, seperti begitu -Selanjutnya, kita akan menggunakan
numba
paket untuk beralih dan mendapatkan hasil akhir kamus hashable. Bersamaan dengan itu, akan ada dua solusi - Satu yang mendapatkan kunci dan nilai secara terpisah menggunakannumba
dan panggilan utama akan zip dan dikonversi ke dict, sementara yang lain akan membuatnumba-supported
tipe dict dan karenanya tidak ada pekerjaan tambahan yang diperlukan oleh fungsi panggilan utama .Dengan demikian, kita akan memiliki
numba
solusi pertama :Dan
numba
solusi kedua sebagai:Pengaturan waktu dengan
cubes.npz
data -Alternatif # 1: Kita dapat mencapai peningkatan lebih lanjut dengan
numexpr
untuk array besar untuk dihitungc1D
, seperti -Ini akan berlaku di semua tempat yang membutuhkan
c1D
.sumber
dtypes
int32
danint64
number of indices per group would be a constant number
bahwa saya mengumpulkan komentar. Apakah itu asumsi yang aman? Juga, apakah Anda mengujicubes.npz
output915791
?cubes.npz
hanya dari output dan itu983234
untuk pendekatan lain yang saya sarankan.Approach #3
untuk kasus umum dari jumlah variabel indeks.Anda mungkin hanya mengulang dan menambahkan indeks setiap elemen ke daftar yang sesuai.
Runtime dapat lebih ditingkatkan dengan menggunakan tobytes () alih-alih mengubah kunci menjadi tuple.
sumber
res[tuple(elem)].append(idx)
butuh 50 detik vs edisires[elem[0], elem[1], elem[2]].append(idx)
yang butuh 30 detik.Anda bisa menggunakan Cython:
tetapi itu tidak akan membuat Anda lebih cepat dari apa yang dilakukan Pandas, meskipun itu adalah yang tercepat setelah itu (dan mungkin
numpy_index
solusi yang berdasarkan), dan tidak datang dengan hukuman memori itu. Koleksi apa yang telah diusulkan sejauh ini ada di sini .Di mesin OP yang seharusnya mendekati ~ 12 detik waktu eksekusi.
sumber