python - সূচকের একটি তালিকা রূপান্তর করতে দ্রুততম উপায় 2 ডি numpy অ্যারে




arrays performance (4)

এই দ্রুততম উপায় হতে পারে না। দ্রুততম উপায় খুঁজে বের করতে আপনাকে বড় অ্যারে ব্যবহার করে এই উত্তরগুলি কার্যকর করার সময়গুলি তুলনা করতে হবে। এখানে আমার সমাধান

output = np.zeros((4,5))
for i, ix in enumerate(a):
    output[i][ix] = 1

# output -> 
#   array([[0, 1, 1, 0, 1],
#   [1, 0, 1, 1, 0],
#   [0, 1, 0, 1, 1],
#   [1, 0, 1, 0, 0]])

আমি সূচক একটি তালিকা আছে

a = [
  [1,2,4],
  [0,2,3],
  [1,3,4],
  [0,2]]

এইগুলির একটি নিমজ্জিত অ্যারে রূপান্তর করার দ্রুততম উপায় কী, যেখানে প্রতিটি সূচক অবস্থান দেখায় যেখানে 1 ঘটবে?

আমি যা চাই তা হল:

output = array([
  [0,1,1,0,1],
  [1,0,1,1,0],
  [0,1,0,1,1],
  [1,0,1,0,0]])

আমি আগে অ্যারের সর্বোচ্চ আকার জানি। আমি জানি প্রতিটি লিস্টের মাধ্যমে আমি লুপ করতে পারি এবং প্রত্যেক ইন্ডেক্স পজিশনে 1 টি ঢোকাতে পারি তবে এটি করার জন্য একটি দ্রুত / ভেক্টরাইজড উপায় আছে?

আমার ব্যবহার ক্ষেত্রে হাজার হাজার সারি / কোল থাকতে পারে এবং আমাকে হাজার হাজার বার করতে হবে, তাই দ্রুততর ভাল।


কিভাবে অ্যারে সূচী ব্যবহার সম্পর্কে? আপনি যদি আপনার ইনপুট সম্পর্কে আরো জানতেন, তবে প্রথমে আপনি একটি রৈখিক অ্যারে রূপান্তর করার জন্য শাস্তি থেকে মুক্ত হতে পারেন।

import numpy as np


def main():
    row_count = 4
    col_count = 5
    a = [[1,2,4],[0,2,3],[1,3,4],[0,2]]

    # iterate through each row, concatenate all indices and convert them to linear

    # numpy append performs copy even if you don't want it, list append is faster
    b = []
    for row_idx, row in enumerate(a):
        b.append(np.array(row, dtype=np.int64) + (row_idx * col_count))

    linear_idxs = np.hstack(b)
    #could skip previous steps if given index inputs well before hand, or in linear index order. 
    c = np.zeros(row_count * col_count)
    c[linear_idxs] = 1
    c = c.reshape(row_count, col_count)
    print(c)


if __name__ == "__main__":
    main()

#output
# [[0. 1. 1. 0. 1.]
#  [1. 0. 1. 1. 0.]
#  [0. 1. 0. 1. 1.]
#  [1. 0. 1. 0. 0.]]

ভাল উপায় হতে পারে না কিন্তু একমাত্র উপায় আমি মনে করতে পারেন:

output = np.zeros((4,5))
for i, (x, y) in enumerate(zip(a, output)):
    y[x] = 1
    output[i] = y
print(output)

কোন আউটপুট:

[[ 0.  1.  1.  0.  1.]
 [ 1.  0.  1.  1.  0.]
 [ 0.  1.  0.  1.  1.]
 [ 1.  0.  1.  0.  0.]]

যদি আপনি Cython ব্যবহার করতে চান এবং আপনি একটি পাঠযোগ্য তৈরি করতে পারেন (অন্তত যদি আপনি Cython মনে করেন না) এবং দ্রুত সমাধান করতে পারেন।

এখানে আমি একটি জুপিটার নোটবইতে কম্পাইল করার জন্য সাইথনের আইপিথন বাইন্ডিং ব্যবহার করছি:

%load_ext cython
%%cython

cimport cython
cimport numpy as cnp
import numpy as np

@cython.boundscheck(False)  # remove this if you cannot guarantee that nrow/ncol are correct
@cython.wraparound(False)
cpdef cnp.int_t[:, :] mseifert(list a, int nrow, int ncol):
    cdef cnp.int_t[:, :] out = np.zeros([nrow, ncol], dtype=int)
    cdef list subl
    cdef int row_idx
    cdef int col_idx
    for row_idx, subl in enumerate(a):
        for col_idx in subl:
            out[row_idx, col_idx] = 1
    return out

এখানে উপস্থাপিত সমাধানগুলির কার্যকারিতা তুলনা করার জন্য আমি আমার লাইব্রেরি simple_benchmark ব্যবহার করি:

নোট করুন যে এটি লগারিদমিক অক্ষ ব্যবহার করে একই সাথে ছোট এবং বড় অ্যারের জন্য পার্থক্য প্রদর্শন করে। আমার বেঞ্চমার্কের মতে আমার ফাংশনটি আসলে সমাধানগুলি দ্রুততম, তবে এটিও মূল্যহীন যে সমস্ত সমাধানগুলি খুব বেশি দূরে নয়।

বেঞ্চমার্কের জন্য ব্যবহৃত সম্পূর্ণ কোডটি এখানে দেওয়া হল:

import numpy as np
from simple_benchmark import BenchmarkBuilder, MultiArgument
import itertools

b = BenchmarkBuilder()

@b.add_function()
def pp(a, nrow, ncol):
    sz = np.fromiter(map(len, a), int, nrow)
    out = np.zeros((nrow, ncol), int)
    out[np.arange(nrow).repeat(sz), np.fromiter(itertools.chain.from_iterable(a), int, sz.sum())] = 1
    return out

@b.add_function()
def ts(a, nrow, ncol):
    out = np.zeros((nrow, ncol), int)
    for i, ix in enumerate(a):
        out[i][ix] = 1
    return out

@b.add_function()
def u9(a, nrow, ncol):
    out = np.zeros((nrow, ncol), int)
    for i, (x, y) in enumerate(zip(a, out)):
        y[x] = 1
        out[i] = y
    return out

b.add_functions([mseifert])

@b.add_arguments("number of rows/columns")
def argument_provider():
    for n in range(2, 13):
        ncols = 2**n
        a = [
            sorted(set(np.random.randint(0, ncols, size=np.random.randint(0, ncols)))) 
            for _ in range(ncols)
        ]
        yield ncols, MultiArgument([a, ncols, ncols])

r = b.run()
r.plot()




numpy