স্বতঃস্ফূর্ত এবং অ-সংগতিপূর্ণ অ্যারেগুলির মধ্যে পার্থক্য কী?


108

ইন numpy ম্যানুয়াল পুনর্নির্মাণ () ফাংশন সম্পর্কে, এটা বলে

>>> a = np.zeros((10, 2))
# A transpose make the array non-contiguous
>>> b = a.T
# Taking a view makes it possible to modify the shape without modifying the
# initial object.
>>> c = b.view()
>>> c.shape = (20)
AttributeError: incompatible shape for a non-contiguous array

আমার প্রশ্নগুলি হ'ল:

  1. অবিচ্ছিন্ন এবং অবিচ্ছিন্ন অ্যারেগুলি কী কী? এটি কি সংলগ্ন মেমরি ব্লকের মতো সিটির মতো একটি স্বচ্ছ মেমরি ব্লক কি?
  2. এই দুটির মধ্যে কোনও পারফরম্যান্সের পার্থক্য রয়েছে কি? কখন আমাদের একটি বা অন্যটি ব্যবহার করা উচিত?
  3. ট্রান্সপোজ কেন অ্যারেটিকে স্বতঃস্ফূর্ত করে তোলে?
  4. কেন c.shape = (20)একটি ত্রুটি ছুড়ে incompatible shape for a non-contiguous array?

আপনার উত্তরের জন্য ধন্যবাদ!

উত্তর:


230

একটি সংক্ষিপ্ত অ্যারে কেবল মেমরির একটি অবিচ্ছিন্ন ব্লকে সঞ্চিত একটি অ্যারে: অ্যারেতে পরবর্তী মানটি অ্যাক্সেস করতে আমরা কেবল পরবর্তী মেমরি ঠিকানায় চলে যাই।

2D অ্যারে বিবেচনা করুন arr = np.arange(12).reshape(3,4)। দেখে মনে হচ্ছে:

এখানে চিত্র বর্ণনা লিখুন

কম্পিউটারের স্মৃতিতে, এর মানগুলি এইভাবে arrসংরক্ষণ করা হয়:

এখানে চিত্র বর্ণনা লিখুন

এর অর্থ arrএকটি সি সংলগ্ন অ্যারে কারণ সারিগুলি মেমরির সংলগ্ন ব্লক হিসাবে সঞ্চিত থাকে। পরবর্তী মেমরি ঠিকানাটি সেই সারিতে পরবর্তী সারির মান ধারণ করে। আমরা যদি একটি কলামটি নীচে সরিয়ে নিতে চাই তবে আমাদের কেবল তিনটি ব্লকের উপরে ঝাঁপিয়ে পড়তে হবে (উদাহরণস্বরূপ 0 থেকে 4 থেকে লাফ দেওয়ার অর্থ আমরা 1,2 এবং 3 এড়িয়ে যেতে পারি)।

অ্যারের সাথে arr.Tস্থানান্তরিত করার অর্থ হ'ল সি স্বাতন্ত্র্য নষ্ট হয়ে যায় কারণ সংলগ্ন সারির এন্ট্রিগুলি সংলগ্ন মেমরি অ্যাড্রেসে আর থাকে না। যাইহোক, arr.Tহয় ফোরট্রান সংলগ্ন যেহেতু কলাম মেমরি সংলগ্ন ব্লক আছে:

এখানে চিত্র বর্ণনা লিখুন


পারফরম্যান্স-ভিত্তিতে, একে অপরের পাশে থাকা মেমরি ঠিকানাগুলিতে অ্যাক্সেস করা খুব বেশি দ্রুত ঠিকানাগুলিতে অ্যাক্সেসের চেয়ে খুব দ্রুত হয় যা বেশি "ছড়িয়ে পড়ে" (র‌্যাম থেকে কোনও মান আনতে সিপিইউতে বেশিরভাগ প্রতিবেশী ঠিকানা আনতে এবং ক্যাশে করা যেতে পারে This) এর অর্থ এই যে অবিচ্ছিন্ন অ্যারেগুলির উপর ক্রিয়াকলাপগুলি প্রায়শই দ্রুত হয়।

সি স্বচ্ছ মেমরির বিন্যাসের ফলস্বরূপ, সারি-ভিত্তিক ক্রিয়াকলাপগুলি কলাম-ওয়াইজ অপারেশনগুলির চেয়ে সাধারণত দ্রুত হয়। উদাহরণস্বরূপ, আপনি সাধারণত এটি খুঁজে পাবেন

np.sum(arr, axis=1) # sum the rows

এর চেয়ে সামান্য দ্রুত:

np.sum(arr, axis=0) # sum the columns

একইভাবে, কলামগুলির ক্রিয়াকলাপগুলি ফরট্রান সংলগ্ন অ্যারেগুলির জন্য কিছুটা দ্রুত হবে।


অবশেষে, কেন আমরা একটি নতুন আকৃতি বরাদ্দ দিয়ে ফোর্টরান সামঞ্জস্যপূর্ণ অ্যারে সমতল করতে পারি না?

>>> arr2 = arr.T
>>> arr2.shape = 12
AttributeError: incompatible shape for a non-contiguous array

এটি সম্ভব হওয়ার জন্য NumPy কে এই জাতীয় সারি arr.Tএকসাথে রেখে দিতে হবে:

এখানে চিত্র বর্ণনা লিখুন

( shapeএ্যাট্রিবিউটটি সেট করা সরাসরি সি অর্ডার ধরে নেয় - যেমন NumPy অপারেশনটি সারিবদ্ধভাবে সম্পাদন করার চেষ্টা করে।)

এটি করা অসম্ভব। যে কোনও অক্ষের জন্য, অ্যারের পরবর্তী উপাদানটিতে পৌঁছানোর জন্য নুমপির একটি ধ্রুব স্ট্রাইড দৈর্ঘ্য (সরানোর জন্য বাইটের সংখ্যা) হওয়া দরকার। arr.Tএই জাতীয়ভাবে সমতলকরণের জন্য অ্যারের ক্রমাগত মানগুলি পুনরুদ্ধার করতে মেমরির সামনে এবং পিছনের দিকে এড়ানো দরকার।

arr2.reshape(12)পরিবর্তে আমরা যদি লিখি, NumPy এআর 2 এর মানগুলিকে মেমরির একটি নতুন ব্লকে অনুলিপি করবে (যেহেতু এটি এই আকারের জন্য মূল ডেটাতে কোনও ভিউ ফেরত দিতে পারে না)।


আমার এটি বুঝতে সমস্যা হচ্ছে, আপনি কি দয়া করে কিছুটা বিস্তারিত বর্ণনা করতে পারেন? মেমরিটিতে অসম্ভব ক্রমের সর্বশেষতম গ্রাফিকাল উপস্থাপনায় আসলে ধাপগুলি আমার মতে অবিচল। উদাহরণস্বরূপ 0 থেকে 1 এ যাওয়ার জন্য স্ট্রাইডটি 1 বাইট (আসুন ধরা যাক প্রতিটি উপাদান একটি বাইট) এবং এটি প্রতিটি কলামের জন্য একই। একইভাবে সারিটির একটি উপাদান থেকে পরের একটিতে যাওয়ার জন্য প্রবাহটি 4 বাইট এবং এটি ধ্রুবকও বটে।
ভেসনোগ

4
@ ভিজনোগ 2D arr2এর 1D আকারের ব্যর্থ পুনঃ আকারটি (12,)সি অর্ডার ব্যবহার করে যার অর্থ যে অক্ষ 1 এর আগে 1 অক্ষরযুক্ত নয় (অর্থাত 1 ডি অ্যারে তৈরি করতে চারটি সারির প্রতিটি একে অপরের পাশে স্থাপন করা দরকার)। অবিচ্ছিন্নভাবে দৈর্ঘ্যের দৈর্ঘ্য (পরিদর্শন করতে জাম্প করতে বাইটস) ব্যবহার করে বাফারের বাইরে (0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11) পূর্ণসংখ্যার এই অনুক্রমটি পড়া অসম্ভব এই উপাদানগুলি ক্রমানুসারে 4, 4, -7, 4, 4, -7, 4, 4, 7, 4, 4) হবে। NumPy প্রতি অক্ষ প্রতিরোধী স্ট্রাইড দৈর্ঘ্য প্রয়োজন।
অ্যালেক্স রিলে

ধন্যবাদ প্রথমে আমি ভেবেছিলাম এটি একটি নতুন অ্যারে তৈরি করবে, তবে এটি পুরানোটির স্মৃতি ব্যবহার করে।
ভেসনোগ

@ অ্যালেক্সরাইলি যখন অ্যারেটিকে শিংগার সি বা এফ অর্ডার করা হয় তখন পর্দার আড়ালে কী ঘটে? উদাহরণস্বরূপ, প্রতিটি এনএক্সডি অ্যারে অ্যারে নিন এবং মুদ্রণ করুন (আরআর [:, :: - 1] .ফ্ল্যাগগুলি) এই পরিস্থিতিতে কি ঘটে? আমি অনুমান করি যে অ্যারেটি আসলেই সি বা এফ অর্ডার করা হয়েছে তবে এর মধ্যে কোনটি? এবং উভয় পতাকা মিথ্যা হলে অদ্ভুতের কোনটি অপ্টিমাইজেশান আমরা হারাব?
জাজং

@ জাজং: নুমপাই অ্যারেটিকে সি বা এফ ক্রম হিসাবে বিবেচনা করে কিনা পুরোপুরি আকার এবং পদক্ষেপের উপর নির্ভর করে (মানদণ্ডটি এখানে রয়েছে )। তাই যখনarr[:, ::-1] একই মেমোরি বাফারের একটি মতামতarr , নম্পপি এটিকে সি বা এফ অর্ডার হিসাবে বিবেচনা করবেন না কারণ এটি একটি "অ-মানক" ক্রমে বাফারের মানগুলিকে অতিক্রম করেছে ...
অ্যালেক্স রিলি

13

12 টি বিভিন্ন অ্যারের মান সহ এই উদাহরণটি সাহায্য করবে:

In [207]: x=np.arange(12).reshape(3,4).copy()

In [208]: x.flags
Out[208]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  ...
In [209]: x.T.flags
Out[209]: 
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  OWNDATA : False
  ...

C orderমান যাতে তারা এ উত্পন্ন হয় আছে। পক্ষান্তরিত বেশী নয়

In [212]: x.reshape(12,)   # same as x.ravel()
Out[212]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [213]: x.T.reshape(12,)
Out[213]: array([ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11])

আপনি উভয়ের 1 ডি ভিউ পেতে পারেন

In [214]: x1=x.T

In [217]: x.shape=(12,)

আকৃতি xপরিবর্তন করা যেতে পারে।

In [220]: x1.shape=(12,)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-220-cf2b1a308253> in <module>()
----> 1 x1.shape=(12,)

AttributeError: incompatible shape for a non-contiguous array

তবে ট্রান্সপোজোর আকার পরিবর্তন করা যায় না। dataএখনও 0,1,2,3,4...আদেশ, যা অ্যাক্সেস করা যাবে না অ্যাক্সেস 0,4,8...একটি 1d অ্যারের মধ্যে।

তবে একটি অনুলিপি x1পরিবর্তন করা যেতে পারে:

In [227]: x2=x1.copy()

In [228]: x2.flags
Out[228]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  ...
In [229]: x2.shape=(12,)

তাকানো stridesএছাড়াও সাহায্য করতে পারে। একটি অগ্রগতি হ'ল পরের মানটি পেতে কতদূর (বাইটে) পদক্ষেপ নিতে হবে। একটি 2 ডি অ্যারের জন্য, 2 টি ধাপের মান হবে:

In [233]: x=np.arange(12).reshape(3,4).copy()

In [234]: x.strides
Out[234]: (16, 4)

পরবর্তী সারিতে পৌঁছতে, 16 বাইট পদক্ষেপ করুন, পরবর্তী কলামটি কেবল 4।

In [235]: x1.strides
Out[235]: (4, 16)

স্থানান্তর কেবল স্ট্রাইজের ক্রম পরিবর্তন করে। পরের সারিটি মাত্র 4 বাইট - অর্থাৎ পরবর্তী সংখ্যা।

In [236]: x.shape=(12,)

In [237]: x.strides
Out[237]: (4,)

আকৃতি পরিবর্তন করলে গতিও বদলে যায় - একসাথে বাফার 4 বাইটের মধ্য দিয়ে পদক্ষেপ নিন।

In [238]: x2=x1.copy()

In [239]: x2.strides
Out[239]: (12, 4)

যদিও x2দেখতে ঠিক তেমন লাগেx1 এটির নিজস্ব ডেটা বাফার রয়েছে, মানগুলি ভিন্ন ক্রমে। পরবর্তী কলামটি এখন 4 বাইট শেষ, যখন পরের সারিটি 12 (3 * 4)।

In [240]: x2.shape=(12,)

In [241]: x2.strides
Out[241]: (4,)

এবং হিসাবে x , আকৃতিটি 1 ডি তে পরিবর্তন করলে ধাপগুলি হ্রাস হয় (4,)

জন্য x1 , ইন তথ্য দিয়ে 0,1,2,...অর্ডার, একটি 1d দীর্ঘ তা দিতে হবে নয় 0,4,8...

__array_interface__ অ্যারে তথ্য প্রদর্শনের আর একটি দরকারী উপায়:

In [242]: x1.__array_interface__
Out[242]: 
{'strides': (4, 16),
 'typestr': '<i4',
 'shape': (4, 3),
 'version': 3,
 'data': (163336056, False),
 'descr': [('', '<i4')]}

দ্য x1তথ্য বাফার ঠিকানার জন্য একই হবে যেমন x, যা দিয়ে ডাটা শেয়ার। x2একটি ভিন্ন বাফার ঠিকানা আছে।

আপনি কমান্ড এবং কমান্ডগুলিতে একটি order='F'পরামিতি যুক্ত করার জন্যও পরীক্ষা করতে পারেন ।copyreshape

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.