NumPy چیست؟ آموزش کامل آرایه، ماتریس و محاسبات برداری با پایتون

آموزش کامل NumPy از ساخت ndarray، Indexing، Reshape و Broadcasting تا آمار، جبر خطی، بهینه‌سازی حافظه و ساخت موتور جست‌وجوی برداری با Cosine Similarity؛ همراه با کدهای عملی.

Share
NumPy چیست؟ آموزش کامل آرایه، ماتریس و محاسبات برداری با پایتون

NumPy یکی از بنیادی‌ترین کتابخانه‌های پایتون برای محاسبات عددی، تحلیل داده، یادگیری ماشین و هوش مصنوعی است. بسیاری از کتابخانه‌های شناخته‌شده مانند Pandas، Scikit-learn، SciPy، OpenCV و ابزارهای یادگیری عمیق، به‌صورت مستقیم یا غیرمستقیم با آرایه‌های NumPy کار می‌کنند.

اگر می‌خواهید پردازش داده، ساخت مدل یادگیری ماشین، محاسبات ماتریسی، کار با تصویر، تحلیل سیگنال، Embedding یا Semantic Search را به‌صورت اصولی یاد بگیرید، درک NumPy اهمیت زیادی دارد.

در این مقاله، NumPy را از پایه تا سطح کاربردی بررسی می‌کنیم و در پایان یک موتور جست‌وجوی برداری کوچک با Cosine Similarity می‌سازیم. این پروژه نشان می‌دهد مفاهیمی مانند Vector، Matrix، Normalization و Matrix Multiplication چگونه در سیستم‌های هوش مصنوعی استفاده می‌شوند.

NumPy چیست؟

NumPy مخفف Numerical Python است. مهم‌ترین ساختار آن ndarray نام دارد؛ یک آرایه چندبعدی که برای نگهداری و پردازش داده‌های هم‌نوع طراحی شده است.

یک آرایه NumPy می‌تواند چنین شکل‌هایی داشته باشد:

Scalar:
42

Vector:
[10, 20, 30]

Matrix:
[[1, 2, 3],
 [4, 5, 6]]

Tensor سه‌بعدی:
[
  [[1, 2], [3, 4]],
  [[5, 6], [7, 8]]
]

طبق مستندات رسمی NumPy، این کتابخانه علاوه بر آرایه‌های چندبعدی، امکاناتی برای عملیات ریاضی، آمار، جبر خطی، تبدیل فوریه، تولید اعداد تصادفی و ورودی و خروجی داده ارائه می‌دهد.

NumPy چه کاربردهایی دارد؟

NumPy در حوزه‌های مختلف استفاده می‌شود:

  • محاسبات برداری و ماتریسی
  • تحلیل داده‌های عددی
  • آماده‌سازی داده برای Machine Learning
  • پردازش تصویر
  • پردازش سیگنال
  • محاسبات آماری
  • شبیه‌سازی و نمونه‌گیری تصادفی
  • کار با Embedding
  • محاسبه Cosine Similarity
  • پیاده‌سازی الگوریتم‌های علمی
  • بهینه‌سازی عملیات عددی
  • تبدیل داده بین کتابخانه‌های مختلف
  • ساخت Batch برای مدل‌های هوش مصنوعی
  • پیاده‌سازی بخش‌هایی از شبکه عصبی

تفاوت NumPy Array و List پایتون

List در Python می‌تواند مقادیر مختلفی را نگهداری کند:

python_list = [
    10,
    "text",
    True,
    3.14,
]

آرایه NumPy معمولاً یک نوع داده مشخص دارد:

import numpy as np

numbers = np.array(
    [
        10,
        20,
        30,
        40,
    ],
    dtype=np.int64,
)

مقایسه کلی:

ویژگیPython ListNumPy Array
نوع دادهمی‌تواند ترکیبی باشدمعمولاً یکسان
محاسبات برداریمستقیم ندارددارد
مصرف حافظه عددیمعمولاً بیشترمعمولاً بهینه‌تر
عملیات ماتریسیمحدودقدرتمند
Broadcastingندارددارد
مناسب محاسبات علمیمحدودبسیار مناسب
استفاده در یادگیری ماشینبا تبدیلمستقیم‌تر

NumPy برای محاسبات عددی بزرگ معمولاً مناسب‌تر است؛ اما برای مجموعه‌های کوچک و ناهمگون، List همچنان انتخاب ساده و مفیدی است.

نصب NumPy

pip install numpy

بررسی نسخه نصب‌شده:

python -c "import numpy; print(numpy.__version__)"

در زمان نگارش این مقاله، NumPy 2.5 نسخه اصلی منتشرشده است. برای مشاهده نسخه فعلی می‌توانید به وب‌سایت رسمی NumPy یا Release Notes مراجعه کنید.

ساخت Virtual Environment

ایجاد محیط مجازی:

python -m venv .venv

فعال‌سازی در Windows PowerShell:

.venv\Scripts\Activate.ps1

فعال‌سازی در Linux و macOS:

source .venv/bin/activate

نصب وابستگی‌ها:

python -m pip install --upgrade pip
python -m pip install numpy matplotlib requests

Import کردن NumPy

روش استاندارد:

import numpy as np

نام اختصاری np در اکثر پروژه‌های Python استفاده می‌شود.

ساخت آرایه یک‌بعدی

numbers = np.array(
    [
        10,
        20,
        30,
        40,
    ]
)

print(numbers)

خروجی:

[10 20 30 40]

بررسی نوع Object:

print(
    type(numbers)
)

خروجی:

<class 'numpy.ndarray'>

ساخت آرایه دوبعدی

matrix = np.array(
    [
        [1, 2, 3],
        [4, 5, 6],
    ]
)

print(matrix)

خروجی:

[[1 2 3]
 [4 5 6]]

ویژگی‌های مهم ndarray

print(
    matrix.ndim
)

print(
    matrix.shape
)

print(
    matrix.size
)

print(
    matrix.dtype
)

print(
    matrix.itemsize
)

print(
    matrix.nbytes
)

معنی ویژگی‌ها:

ویژگیکاربرد
ndimتعداد Dimensionها
shapeاندازه هر Dimension
sizeتعداد کل Elementها
dtypeنوع داده
itemsizeحافظه هر Element بر حسب Byte
nbytesحافظه کل داده آرایه

برای ماتریس قبلی:

ndim = 2
shape = (2, 3)
size = 6

انتخاب dtype مناسب

integers = np.array(
    [1, 2, 3],
    dtype=np.int32,
)

floats = np.array(
    [1.0, 2.0, 3.0],
    dtype=np.float32,
)

انواع رایج:

dtypeکاربرد
int8عدد صحیح ۸ بیتی
int16عدد صحیح ۱۶ بیتی
int32عدد صحیح ۳۲ بیتی
int64عدد صحیح ۶۴ بیتی
float16اعشاری کم‌دقت
float32اعشاری رایج در یادگیری ماشین
float64اعشاری با دقت بیشتر
boolمقدار منطقی
complex64عدد مختلط
str_رشته

نوع داده کوچک‌تر می‌تواند حافظه کمتری مصرف کند؛ اما باید محدوده مقدار و دقت موردنیاز را بررسی کنید.

برای نمونه، int8 فقط محدوده کوچکی از اعداد را نگهداری می‌کند و استفاده اشتباه از آن ممکن است باعث Overflow شود.

تبدیل dtype

numbers = np.array(
    [
        1.2,
        2.7,
        3.9,
    ]
)

integer_numbers = numbers.astype(
    np.int32
)

print(integer_numbers)

خروجی:

[1 2 3]

تبدیل Float به Integer بخش اعشاری را حذف می‌کند و Round انجام نمی‌دهد.

برای Round:

rounded = np.rint(
    numbers
).astype(
    np.int32
)

روش‌های ساخت آرایه

آرایه صفر

zeros = np.zeros(
    shape=(3, 4),
    dtype=np.float32,
)

آرایه یک

ones = np.ones(
    shape=(2, 3),
    dtype=np.float32,
)

آرایه با مقدار ثابت

filled = np.full(
    shape=(2, 3),
    fill_value=7,
)

ماتریس همانی

identity = np.eye(
    4,
    dtype=np.float32,
)

دنباله عددی با arange

values = np.arange(
    start=0,
    stop=10,
    step=2,
)

خروجی:

[0 2 4 6 8]

مقدار stop در خروجی قرار نمی‌گیرد.

دنباله با linspace

values = np.linspace(
    start=0,
    stop=1,
    num=6,
)

خروجی:

[0.  0.2 0.4 0.6 0.8 1. ]

تفاوت:

  • arange بر اساس Step کار می‌کند.
  • linspace تعداد نقاط را مشخص می‌کند.

برای اعداد اعشاری، linspace در بسیاری از موارد قابل‌پیش‌بینی‌تر است.

روش‌های رسمی ایجاد آرایه در راهنمای Array Creation توضیح داده شده‌اند.

Indexing در NumPy

آرایه یک‌بعدی:

values = np.array(
    [
        10,
        20,
        30,
        40,
        50,
    ]
)

print(
    values[0]
)

print(
    values[-1]
)

ماتریس:

matrix = np.array(
    [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ]
)

print(
    matrix[1, 2]
)

خروجی:

6

انتخاب یک ردیف:

second_row = matrix[1, :]

انتخاب یک ستون:

second_column = matrix[:, 1]

انتخاب بخشی از ماتریس:

subset = matrix[
    0:2,
    1:3,
]

Slicing

values = np.array(
    [
        10,
        20,
        30,
        40,
        50,
        60,
    ]
)

print(
    values[1:5]
)

print(
    values[::2]
)

print(
    values[::-1]
)

خروجی:

[20 30 40 50]
[10 30 50]
[60 50 40 30 20 10]

Boolean Indexing

scores = np.array(
    [
        42,
        78,
        91,
        65,
        88,
    ]
)

mask = scores >= 70

print(mask)

print(
    scores[mask]
)

می‌توان شرط را مستقیم نوشت:

selected_scores = scores[
    scores >= 70
]

ترکیب شرط‌ها:

selected_scores = scores[
    (scores >= 70)
    & (scores <= 90)
]

استفاده از and و or برای آرایه NumPy صحیح نیست. باید از &، | و پرانتز استفاده کنید.

Advanced Indexing

values = np.array(
    [
        10,
        20,
        30,
        40,
        50,
    ]
)

indexes = np.array(
    [
        0,
        2,
        4,
    ]
)

selected = values[
    indexes
]

انتخاب چند ردیف و ستون:

matrix = np.arange(
    20
).reshape(
    4,
    5,
)

rows = np.array(
    [
        0,
        2,
    ]
)

columns = np.array(
    [
        1,
        3,
    ]
)

selected = matrix[
    np.ix_(
        rows,
        columns,
    )
]

راهنمای کامل Indexing در مستندات Indexing آرایه‌های NumPy موجود است.

تفاوت View و Copy

یکی از مهم‌ترین نکات NumPy این است که Slicing معمولاً یک View از آرایه اصلی ایجاد می‌کند.

original = np.array(
    [
        10,
        20,
        30,
        40,
    ]
)

view = original[1:3]

view[0] = 999

print(original)

خروجی:

[ 10 999  30  40]

با تغییر view، آرایه اصلی نیز تغییر کرده است.

اگر Copy مستقل نیاز دارید:

copied = original[
    1:3
].copy()

copied[0] = 500

print(original)
print(copied)

مستندات NumPy توضیح می‌دهد که Basic Indexing معمولاً View ایجاد می‌کند، درحالی‌که Advanced Indexing معمولاً Copy برمی‌گرداند. جزئیات در راهنمای Copies and Views آمده است.

تغییر Shape آرایه

values = np.arange(
    12
)

matrix = values.reshape(
    3,
    4,
)

print(matrix)

خروجی:

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

استفاده از -1 برای محاسبه خودکار یک Dimension:

matrix = values.reshape(
    2,
    -1,
)

NumPy Dimension دوم را برابر ۶ قرار می‌دهد.

تعداد Elementهای Shape جدید باید با تعداد Elementهای آرایه برابر باشد.

تبدیل ماتریس به Vector

با reshape:

vector = matrix.reshape(
    -1
)

با ravel:

vector = matrix.ravel()

با flatten:

vector = matrix.flatten()

تفاوت مهم:

  • flatten همیشه Copy ایجاد می‌کند.
  • ravel در صورت امکان View برمی‌گرداند.
  • reshape(-1) نیز ممکن است View ایجاد کند.

اگر قرار است خروجی را تغییر دهید و آرایه اصلی نباید تغییر کند، از .copy() یا flatten() استفاده کنید.

اضافه یا حذف Dimension

vector = np.array(
    [
        1,
        2,
        3,
    ]
)

row_vector = vector[
    np.newaxis,
    :
]

column_vector = vector[
    :,
    np.newaxis
]

Shapeها:

vector:        (3,)
row_vector:    (1, 3)
column_vector: (3, 1)

روش دیگر:

expanded = np.expand_dims(
    vector,
    axis=0,
)

حذف Dimensionهای دارای اندازه یک:

squeezed = np.squeeze(
    expanded
)

Transpose

matrix = np.array(
    [
        [1, 2, 3],
        [4, 5, 6],
    ]
)

transposed = matrix.T

Shape اولیه:

(2, 3)

Shape جدید:

(3, 2)

برای Tensor چندبعدی:

tensor = np.zeros(
    (
        2,
        3,
        4,
    )
)

reordered = np.transpose(
    tensor,
    axes=(
        2,
        0,
        1,
    ),
)

عملیات برداری

first = np.array(
    [
        1,
        2,
        3,
    ]
)

second = np.array(
    [
        4,
        5,
        6,
    ]
)

جمع:

result = first + second

تفریق:

result = first - second

ضرب Element-wise:

result = first * second

تقسیم:

result = first / second

توان:

result = first ** 2

این عملیات بدون Loop صریح Python روی تمام Elementها اجرا می‌شوند.

Vectorization چیست؟

روش معمول با Loop:

values = [
    1,
    2,
    3,
    4,
]

squared = []

for value in values:
    squared.append(
        value ** 2
    )

نسخه NumPy:

values = np.array(
    [
        1,
        2,
        3,
        4,
    ]
)

squared = values ** 2

Vectorization کد را کوتاه‌تر می‌کند و معمولاً عملکرد بهتری دارد؛ زیرا بخش اصلی محاسبه در کد بهینه‌شده کتابخانه اجرا می‌شود.

مقایسه سرعت Loop و NumPy

import time
import numpy as np


number_of_items = 1_000_000

python_values = list(
    range(
        number_of_items
    )
)

start = time.perf_counter()

python_result = [
    value * 2
    for value in python_values
]

python_time = (
    time.perf_counter()
    - start
)


numpy_values = np.arange(
    number_of_items
)

start = time.perf_counter()

numpy_result = (
    numpy_values * 2
)

numpy_time = (
    time.perf_counter()
    - start
)

print(
    "Python time:",
    python_time,
)

print(
    "NumPy time:",
    numpy_time,
)

نتیجه دقیق به سیستم، نسخه Python، dtype و نوع عملیات بستگی دارد؛ بنابراین بهتر است به‌جای تکرار ادعاهای کلی، Benchmark را روی Workflow واقعی خود اجرا کنید.

Broadcasting چیست؟

Broadcasting به NumPy اجازه می‌دهد عملیات را بین آرایه‌هایی با Shape متفاوت اما سازگار انجام دهد.

مثال ساده:

values = np.array(
    [
        10,
        20,
        30,
    ]
)

result = values + 5

عدد ۵ به‌صورت منطقی برای تمام Elementها استفاده می‌شود:

[15 25 35]

مثال ماتریس و Vector:

matrix = np.array(
    [
        [1, 2, 3],
        [4, 5, 6],
    ]
)

offset = np.array(
    [
        10,
        20,
        30,
    ]
)

result = matrix + offset

خروجی:

[[11 22 33]
 [14 25 36]]

قوانین Broadcasting

NumPy Shapeها را از سمت راست مقایسه می‌کند. دو Dimension زمانی سازگار هستند که:

  • اندازه آن‌ها برابر باشد؛ یا
  • اندازه یکی از آن‌ها برابر یک باشد.

مثال سازگار:

Matrix shape: (4, 3)
Vector shape:    (3,)

مثال ناسازگار:

Matrix shape: (4, 3)
Vector shape:    (4,)

برای سازگارکردن مثال دوم:

vector = np.array(
    [
        10,
        20,
        30,
        40,
    ]
).reshape(
    4,
    1,
)

result = matrix + vector

Broadcasting امکان Vectorization را فراهم می‌کند و معمولاً بدون ساخت Copyهای غیرضروری کار می‌کند. جزئیات در راهنمای رسمی Broadcasting توضیح داده شده است.

توابع آماری NumPy

values = np.array(
    [
        10,
        20,
        30,
        40,
        50,
    ],
    dtype=np.float64,
)

مجموع:

total = np.sum(
    values
)

میانگین:

average = np.mean(
    values
)

میانه:

median = np.median(
    values
)

انحراف معیار:

standard_deviation = np.std(
    values
)

واریانس:

variance = np.var(
    values
)

کمینه و بیشینه:

minimum = np.min(
    values
)

maximum = np.max(
    values
)

صدک:

percentile_90 = np.percentile(
    values,
    90,
)

مفهوم axis

matrix = np.array(
    [
        [1, 2, 3],
        [4, 5, 6],
    ]
)

مجموع تمام Elementها:

print(
    matrix.sum()
)

مجموع هر ستون:

print(
    matrix.sum(
        axis=0
    )
)

خروجی:

[5 7 9]

مجموع هر ردیف:

print(
    matrix.sum(
        axis=1
    )
)

خروجی:

[ 6 15]

قاعده کاربردی:

  • axis=0 یعنی Dimension ردیف‌ها حذف و نتیجه برای ستون‌ها محاسبه شود.
  • axis=1 یعنی Dimension ستون‌ها حذف و نتیجه برای ردیف‌ها محاسبه شود.

برای Tensorهای چندبعدی بهتر است همیشه Shape ورودی و خروجی را بررسی کنید.

حفظ Dimension با keepdims

row_means = matrix.mean(
    axis=1,
    keepdims=True,
)

Shape نتیجه:

(2, 1)

این ویژگی در Broadcasting مفید است:

centered = (
    matrix
    - row_means
)

مدیریت NaN

values = np.array(
    [
        10.0,
        np.nan,
        30.0,
        40.0,
    ]
)

میانگین معمولی:

print(
    np.mean(values)
)

خروجی nan است.

میانگین با نادیده‌گرفتن NaN:

print(
    np.nanmean(values)
)

سایر توابع:

np.nansum(values)
np.nanmin(values)
np.nanmax(values)
np.nanmedian(values)
np.nanstd(values)

شناسایی NaN:

missing_mask = np.isnan(
    values
)

جایگزینی:

clean_values = np.nan_to_num(
    values,
    nan=0.0,
    posinf=1_000.0,
    neginf=-1_000.0,
)

جایگزینی خودکار NaN با صفر همیشه انتخاب مناسبی نیست. روش جایگزینی باید بر اساس معنی داده تعیین شود.

استفاده از np.where

scores = np.array(
    [
        45,
        72,
        88,
        61,
    ]
)

labels = np.where(
    scores >= 70,
    "accepted",
    "review",
)

جایگزینی مقادیر منفی:

values = np.array(
    [
        10,
        -5,
        20,
        -3,
    ]
)

clean_values = np.where(
    values < 0,
    0,
    values,
)

محدودکردن مقدار با clip

probabilities = np.array(
    [
        -0.2,
        0.3,
        0.8,
        1.4,
    ]
)

clipped = np.clip(
    probabilities,
    0.0,
    1.0,
)

خروجی:

[0.  0.3 0.8 1. ]

مرتب‌سازی

values = np.array(
    [
        30,
        10,
        50,
        20,
    ]
)

sorted_values = np.sort(
    values
)

Indexهای مرتب‌سازی:

sorted_indexes = np.argsort(
    values
)

مرتب‌سازی نزولی:

descending_indexes = np.argsort(
    values
)[::-1]

descending_values = values[
    descending_indexes
]

این روش در رتبه‌بندی نتایج جست‌وجوی برداری نیز استفاده می‌شود.

مقادیر یکتا

labels = np.array(
    [
        "a",
        "b",
        "a",
        "c",
        "b",
        "a",
    ]
)

unique_values = np.unique(
    labels
)

همراه تعداد تکرار:

values, counts = np.unique(
    labels,
    return_counts=True,
)

ساخت Dictionary:

frequency = dict(
    zip(
        values.tolist(),
        counts.tolist(),
    )
)

اتصال آرایه‌ها

first = np.array(
    [
        1,
        2,
        3,
    ]
)

second = np.array(
    [
        4,
        5,
        6,
    ]
)

با concatenate:

combined = np.concatenate(
    [
        first,
        second,
    ]
)

ساخت ماتریس ردیفی:

stacked_rows = np.vstack(
    [
        first,
        second,
    ]
)

ساخت ماتریس ستونی:

stacked_columns = np.column_stack(
    [
        first,
        second,
    ]
)

ساخت Dimension جدید:

stacked = np.stack(
    [
        first,
        second,
    ],
    axis=0,
)

تفاوت مهم این است که stack یک Dimension جدید ایجاد می‌کند، اما concatenate روی Dimension موجود اتصال انجام می‌دهد.

تقسیم آرایه

values = np.arange(
    12
)

تقسیم مساوی:

parts = np.split(
    values,
    3,
)

تقسیم نامساوی:

parts = np.array_split(
    values,
    5,
)

تقسیم ماتریس:

matrix = np.arange(
    24
).reshape(
    6,
    4,
)

row_parts = np.vsplit(
    matrix,
    3,
)

column_parts = np.hsplit(
    matrix,
    2,
)

تولید اعداد تصادفی

روش پیشنهادی استفاده از Generator است:

rng = np.random.default_rng(
    seed=42
)

عدد تصادفی بین صفر و یک:

values = rng.random(
    size=5
)

عدد صحیح:

integers = rng.integers(
    low=0,
    high=100,
    size=10,
)

توزیع نرمال:

normal_values = rng.normal(
    loc=0.0,
    scale=1.0,
    size=1000,
)

انتخاب تصادفی:

selected = rng.choice(
    [
        "basic",
        "pro",
        "team",
    ],
    size=20,
    p=[
        0.60,
        0.30,
        0.10,
    ],
)

Shuffle:

values = np.arange(
    10
)

rng.shuffle(
    values
)

مستندات مقدماتی NumPy نیز استفاده از np.random.default_rng() را برای ساخت Generator نشان می‌دهد. برای مطالعه بیشتر می‌توانید راهنمای NumPy برای مبتدیان را ببینید.

ضرب ماتریسی

ضرب Element-wise:

first = np.array(
    [
        [1, 2],
        [3, 4],
    ]
)

second = np.array(
    [
        [5, 6],
        [7, 8],
    ]
)

elementwise = (
    first * second
)

ضرب ماتریسی:

matrix_product = (
    first @ second
)

یا:

matrix_product = np.matmul(
    first,
    second,
)

این دو عملیات یکسان نیستند.

Dot Product

first = np.array(
    [
        1.0,
        2.0,
        3.0,
    ]
)

second = np.array(
    [
        4.0,
        5.0,
        6.0,
    ]
)

dot_product = np.dot(
    first,
    second,
)

یا:

dot_product = (
    first @ second
)

فرمول Dot Product:

a · b =
a1 × b1
+ a2 × b2
+ ...
+ an × bn

جبر خطی با NumPy

matrix = np.array(
    [
        [2.0, 1.0],
        [1.0, 3.0],
    ]
)

دترمینان:

determinant = np.linalg.det(
    matrix
)

معکوس:

inverse = np.linalg.inv(
    matrix
)

مقادیر و بردارهای ویژه:

eigenvalues, eigenvectors = (
    np.linalg.eig(
        matrix
    )
)

Norm:

norm = np.linalg.norm(
    matrix
)

حل دستگاه معادلات:

coefficients = np.array(
    [
        [2.0, 1.0],
        [1.0, 3.0],
    ]
)

targets = np.array(
    [
        8.0,
        13.0,
    ]
)

solution = np.linalg.solve(
    coefficients,
    targets,
)

برای حل دستگاه، استفاده از solve معمولاً از محاسبه مستقیم معکوس مناسب‌تر است.

Normalization بردار

vector = np.array(
    [
        3.0,
        4.0,
    ],
    dtype=np.float32,
)

norm = np.linalg.norm(
    vector
)

normalized_vector = (
    vector / norm
)

خروجی:

[0.6 0.8]

برای جلوگیری از تقسیم بر صفر:

epsilon = 1e-12

normalized_vector = (
    vector
    / max(
        norm,
        epsilon,
    )
)

Normalization چند بردار

vectors = np.array(
    [
        [3.0, 4.0],
        [1.0, 0.0],
        [0.0, 2.0],
    ],
    dtype=np.float32,
)

norms = np.linalg.norm(
    vectors,
    axis=1,
    keepdims=True,
)

normalized_vectors = (
    vectors
    / np.maximum(
        norms,
        1e-12,
    )
)

استفاده از keepdims=True باعث می‌شود Shape برای Broadcasting مناسب باقی بماند.

Cosine Similarity چیست؟

Cosine Similarity میزان هم‌جهتی دو بردار را اندازه‌گیری می‌کند:

cosine_similarity(a, b) =
dot(a, b) / (norm(a) × norm(b))

کد NumPy:

def cosine_similarity(
    first: np.ndarray,
    second: np.ndarray,
) -> float:
    first = np.asarray(
        first,
        dtype=np.float32,
    )

    second = np.asarray(
        second,
        dtype=np.float32,
    )

    denominator = (
        np.linalg.norm(first)
        * np.linalg.norm(second)
    )

    if denominator == 0:
        return 0.0

    return float(
        np.dot(
            first,
            second,
        )
        / denominator
    )

اگر بردارها از قبل L2-normalized باشند:

Cosine Similarity = Dot Product

این نکته امکان محاسبه سریع شباهت تعداد زیادی بردار را فراهم می‌کند.

پروژه عملی: ساخت موتور جست‌وجوی برداری با NumPy

فرض کنید برای چند سند، Embedding ذخیره کرده‌ایم. برای قابل‌اجرا بودن مثال، بردارها داخل کد قرار گرفته‌اند.

در پروژه واقعی، این بردارها توسط یک Embedding Model تولید می‌شوند و باید تمام آن‌ها با یک مدل و تنظیمات یکسان ساخته شوند.

import numpy as np


documents = [
    {
        "id": "doc_001",
        "title": (
            "آموزش ساخت چت‌بات "
            "با پایتون"
        ),
    },
    {
        "id": "doc_002",
        "title": (
            "تحلیل فایل CSV "
            "با Pandas"
        ),
    },
    {
        "id": "doc_003",
        "title": (
            "ساخت جست‌وجوی معنایی "
            "با Embedding"
        ),
    },
    {
        "id": "doc_004",
        "title": (
            "آموزش تولید تصویر "
            "با هوش مصنوعی"
        ),
    },
    {
        "id": "doc_005",
        "title": (
            "مدیریت هزینه API "
            "هوش مصنوعی"
        ),
    },
]

بردارهای آزمایشی:

document_embeddings = np.array(
    [
        [
            0.82,
            0.71,
            0.15,
            0.10,
            0.22,
            0.18,
        ],
        [
            0.20,
            0.35,
            0.88,
            0.74,
            0.12,
            0.16,
        ],
        [
            0.74,
            0.68,
            0.30,
            0.25,
            0.80,
            0.72,
        ],
        [
            0.22,
            0.19,
            0.14,
            0.18,
            0.84,
            0.76,
        ],
        [
            0.41,
            0.38,
            0.44,
            0.35,
            0.28,
            0.90,
        ],
    ],
    dtype=np.float32,
)

بردار Query آزمایشی:

query_embedding = np.array(
    [
        0.78,
        0.70,
        0.26,
        0.20,
        0.83,
        0.69,
    ],
    dtype=np.float32,
)

این بردارها فقط برای نمایش محاسبات هستند و کیفیت Semantic Search واقعی را نشان نمی‌دهند.

اعتبارسنجی Shapeها

if document_embeddings.ndim != 2:
    raise ValueError(
        "Document embeddings "
        "must be a 2D array."
    )

if query_embedding.ndim != 1:
    raise ValueError(
        "Query embedding "
        "must be a 1D array."
    )

if (
    document_embeddings.shape[1]
    != query_embedding.shape[0]
):
    raise ValueError(
        "Embedding dimensions "
        "do not match."
    )

if (
    document_embeddings.shape[0]
    != len(documents)
):
    raise ValueError(
        "Number of documents "
        "and embeddings must match."
    )

Normalization اسناد

document_norms = np.linalg.norm(
    document_embeddings,
    axis=1,
    keepdims=True,
)

safe_document_norms = np.maximum(
    document_norms,
    1e-12,
)

normalized_documents = (
    document_embeddings
    / safe_document_norms
)

Normalization کوئری:

query_norm = np.linalg.norm(
    query_embedding
)

if query_norm < 1e-12:
    raise ValueError(
        "Query embedding "
        "cannot be a zero vector."
    )

normalized_query = (
    query_embedding
    / query_norm
)

محاسبه شباهت تمام اسناد

similarities = (
    normalized_documents
    @ normalized_query
)

Shapeها:

normalized_documents: (5, 6)
normalized_query:      (6,)
similarities:          (5,)

NumPy با ضرب ماتریسی، شباهت Query را با تمام اسناد در یک عملیات محاسبه می‌کند.

انتخاب Top K

top_k = 3

top_indexes = np.argsort(
    similarities
)[::-1][:top_k]

ساخت نتیجه:

results = []

for index in top_indexes:
    results.append(
        {
            "id": (
                documents[index]["id"]
            ),
            "title": (
                documents[index]["title"]
            ),
            "score": round(
                float(
                    similarities[index]
                ),
                6,
            ),
        }
    )

for result in results:
    print(result)

انتخاب Top K با argpartition

برای تعداد بسیار زیاد بردار، مرتب‌سازی کامل ضروری نیست:

top_k = 3

candidate_indexes = np.argpartition(
    similarities,
    -top_k,
)[-top_k:]

top_indexes = candidate_indexes[
    np.argsort(
        similarities[
            candidate_indexes
        ]
    )[::-1]
]

argpartition ابتدا کاندیداهای Top K را پیدا می‌کند و سپس فقط همان بخش مرتب می‌شود.

ساخت کلاس VectorSearchEngine

import numpy as np


class VectorSearchEngine:
    def __init__(
        self,
        documents: list[dict],
        embeddings: np.ndarray,
    ):
        embeddings = np.asarray(
            embeddings,
            dtype=np.float32,
        )

        if embeddings.ndim != 2:
            raise ValueError(
                "Embeddings must "
                "be a 2D array."
            )

        if (
            embeddings.shape[0]
            != len(documents)
        ):
            raise ValueError(
                "Number of documents "
                "and vectors must match."
            )

        norms = np.linalg.norm(
            embeddings,
            axis=1,
            keepdims=True,
        )

        zero_vectors = (
            norms[:, 0] < 1e-12
        )

        if np.any(
            zero_vectors
        ):
            invalid_indexes = np.flatnonzero(
                zero_vectors
            ).tolist()

            raise ValueError(
                "Zero document vectors "
                "at indexes: "
                f"{invalid_indexes}"
            )

        self.documents = documents

        self.embeddings = (
            embeddings
            / norms
        )

        self.dimension = int(
            embeddings.shape[1]
        )

    def search(
        self,
        query_embedding: np.ndarray,
        top_k: int = 5,
        minimum_score: float | None = None,
    ) -> list[dict]:
        query = np.asarray(
            query_embedding,
            dtype=np.float32,
        )

        if query.ndim != 1:
            raise ValueError(
                "Query must be "
                "a 1D vector."
            )

        if (
            query.shape[0]
            != self.dimension
        ):
            raise ValueError(
                "Query dimension does "
                "not match index dimension."
            )

        query_norm = np.linalg.norm(
            query
        )

        if query_norm < 1e-12:
            raise ValueError(
                "Query cannot be "
                "a zero vector."
            )

        query = (
            query / query_norm
        )

        scores = (
            self.embeddings
            @ query
        )

        top_k = min(
            max(
                int(top_k),
                1,
            ),
            len(self.documents),
        )

        candidate_indexes = (
            np.argpartition(
                scores,
                -top_k,
            )[-top_k:]
        )

        sorted_indexes = (
            candidate_indexes[
                np.argsort(
                    scores[
                        candidate_indexes
                    ]
                )[::-1]
            ]
        )

        results = []

        for index in sorted_indexes:
            score = float(
                scores[index]
            )

            if (
                minimum_score
                is not None
                and score
                < minimum_score
            ):
                continue

            results.append(
                {
                    **self.documents[
                        index
                    ],
                    "score": round(
                        score,
                        6,
                    ),
                }
            )

        return results

استفاده:

engine = VectorSearchEngine(
    documents=documents,
    embeddings=(
        document_embeddings
    ),
)

results = engine.search(
    query_embedding=(
        query_embedding
    ),
    top_k=3,
)

print(results)

جست‌وجوی Batch

اگر چند Query داشته باشیم:

query_embeddings = np.array(
    [
        [
            0.78,
            0.70,
            0.26,
            0.20,
            0.83,
            0.69,
        ],
        [
            0.18,
            0.32,
            0.90,
            0.72,
            0.10,
            0.20,
        ],
    ],
    dtype=np.float32,
)

Normalization:

query_norms = np.linalg.norm(
    query_embeddings,
    axis=1,
    keepdims=True,
)

normalized_queries = (
    query_embeddings
    / np.maximum(
        query_norms,
        1e-12,
    )
)

محاسبه ماتریس شباهت:

similarity_matrix = (
    normalized_queries
    @ normalized_documents.T
)

Shape خروجی:

(number_of_queries, number_of_documents)

هر ردیف شامل Scoreهای یک Query برای تمام اسناد است.

ذخیره Embeddingها

ذخیره یک آرایه:

np.save(
    "document_embeddings.npy",
    document_embeddings,
)

بارگذاری:

loaded_embeddings = np.load(
    "document_embeddings.npy"
)

ذخیره چند آرایه:

np.savez_compressed(
    "vector_index.npz",
    embeddings=(
        document_embeddings
    ),
    document_ids=np.array(
        [
            item["id"]
            for item in documents
        ]
    ),
)

بارگذاری:

index_data = np.load(
    "vector_index.npz",
    allow_pickle=False,
)

loaded_embeddings = (
    index_data["embeddings"]
)

loaded_ids = (
    index_data["document_ids"]
)

تا زمانی که نیازی وجود ندارد، allow_pickle=True را فعال نکنید. آرایه‌های عددی و رشته‌ای استاندارد را می‌توان بدون Pickle ذخیره کرد.

ذخیره Metadata اسناد

import json

with open(
    "documents.json",
    "w",
    encoding="utf-8",
) as file:
    json.dump(
        documents,
        file,
        ensure_ascii=False,
        indent=2,
    )

بارگذاری:

with open(
    "documents.json",
    "r",
    encoding="utf-8",
) as file:
    loaded_documents = (
        json.load(file)
    )

همراه Index بهتر است موارد زیر ذخیره شوند:

  • Model ID تولیدکننده Embedding
  • Dimension بردار
  • وضعیت Normalization
  • تاریخ ساخت Index
  • تعداد اسناد
  • نسخه داده
  • شناسه هر سند
  • الگوریتم Similarity

نباید Embeddingهای تولیدشده توسط مدل‌های مختلف را بدون بررسی داخل یک Index قرار دهید.

محاسبه شباهت در Batchهای کوچک

اگر تمام بردارها هم‌زمان در حافظه جا نمی‌شوند:

def batched_vector_search(
    document_embeddings: np.ndarray,
    query_embedding: np.ndarray,
    batch_size: int = 100_000,
    top_k: int = 10,
) -> list[tuple[int, float]]:
    query = np.asarray(
        query_embedding,
        dtype=np.float32,
    )

    query_norm = np.linalg.norm(
        query
    )

    if query_norm < 1e-12:
        raise ValueError(
            "Query vector is zero."
        )

    query = (
        query / query_norm
    )

    candidates = []

    for start in range(
        0,
        len(document_embeddings),
        batch_size,
    ):
        end = min(
            start + batch_size,
            len(document_embeddings),
        )

        batch = np.asarray(
            document_embeddings[
                start:end
            ],
            dtype=np.float32,
        )

        batch_norms = np.linalg.norm(
            batch,
            axis=1,
            keepdims=True,
        )

        normalized_batch = (
            batch
            / np.maximum(
                batch_norms,
                1e-12,
            )
        )

        scores = (
            normalized_batch
            @ query
        )

        local_k = min(
            top_k,
            len(scores),
        )

        local_indexes = np.argpartition(
            scores,
            -local_k,
        )[-local_k:]

        for local_index in local_indexes:
            candidates.append(
                (
                    start
                    + int(local_index),
                    float(
                        scores[
                            local_index
                        ]
                    ),
                )
            )

    candidates.sort(
        key=lambda item: item[1],
        reverse=True,
    )

    return candidates[
        :top_k
    ]

این روش آموزشی است. برای میلیون‌ها بردار، جست‌وجوی Approximate Nearest Neighbor و Vector Database معمولاً مقیاس‌پذیرتر خواهد بود.

تفاوت NumPy و Vector Database

ویژگیNumPyVector Database
راه‌اندازیبسیار سادهنیازمند سرویس یا نرم‌افزار
جست‌وجوی Exactمناسببسته به تنظیمات
مقیاس کوچکبسیار مناسبممکن است اضافه باشد
Metadata Filterباید دستی ساخته شودمعمولاً داخلی
Index تقریبیبه‌صورت پیش‌فرض نداردمعمولاً دارد
Persistenceفایل .npy یا .npzداخلی
آپدیت آنلایننیازمند طراحی دستیمعمولاً پشتیبانی می‌شود
مقیاس میلیون‌ها Vectorمحدودترمناسب‌تر

NumPy برای Prototype، تست الگوریتم، دیتاست کوچک و درک محاسبات بسیار مناسب است.

توضیح نتایج با API درواره

می‌توان نتایج جست‌وجوی برداری را برای تولید پاسخ یا خلاصه به یک مدل زبانی ارسال کرد. برای دسترسی به مدل‌های مختلف از طریق API می‌توانید از درواره استفاده کنید.

تنظیم متغیرهای محیطی:

export DARVAREH_API_KEY="YOUR_DARVAREH_API_KEY"
export DARVAREH_MODEL_ID="YOUR_MODEL_ID"

در Windows PowerShell:

$env:DARVAREH_API_KEY="YOUR_DARVAREH_API_KEY"
$env:DARVAREH_MODEL_ID="YOUR_MODEL_ID"

ارسال نتایج:

import json
import os
import requests


api_key = os.environ[
    "DARVAREH_API_KEY"
]

model_id = os.environ[
    "DARVAREH_MODEL_ID"
]

retrieved_results = (
    engine.search(
        query_embedding,
        top_k=3,
    )
)

context_json = json.dumps(
    retrieved_results,
    ensure_ascii=False,
    indent=2,
)

response = requests.post(
    "https://api.darvareh.ir/v1/chat/completions",
    headers={
        "Authorization": (
            f"Bearer {api_key}"
        ),
        "Content-Type": (
            "application/json"
        ),
    },
    json={
        "model": model_id,
        "messages": [
            {
                "role": "system",
                "content": (
                    "فقط بر اساس نتایج "
                    "بازیابی‌شده پاسخ بده. "
                    "اگر اطلاعات کافی نیست، "
                    "شفاف اعلام کن."
                ),
            },
            {
                "role": "user",
                "content": f"""
نتایج بازیابی‌شده:

{context_json}

این نتایج را به فارسی و به ترتیب ارتباط خلاصه کن.
Scoreها را تغییر نده و اطلاعات جدیدی اختراع نکن.
""",
            },
        ],
        "temperature": 0.1,
    },
    timeout=60,
)

response.raise_for_status()

data = response.json()

answer = data[
    "choices"
][0]["message"]["content"]

print(answer)

برای انتخاب Model ID و مشاهده قیمت به‌روز، صفحه مدل‌های درواره را بررسی کنید.

در سیستم واقعی بهتر است به‌جای عنوان، متن Chunkهای بازیابی‌شده همراه شناسه منبع در اختیار مدل قرار گیرد.

ارتباط NumPy با شبکه عصبی

ورودی شبکه عصبی معمولاً یک Tensor عددی است. NumPy می‌تواند برای آماده‌سازی این داده استفاده شود.

مثال یک Batch:

batch = np.array(
    [
        [
            0.2,
            0.5,
            0.8,
        ],
        [
            0.1,
            0.9,
            0.3,
        ],
    ],
    dtype=np.float32,
)

وزن‌ها:

weights = np.array(
    [
        [
            0.4,
            0.2,
        ],
        [
            0.7,
            0.1,
        ],
        [
            0.3,
            0.8,
        ],
    ],
    dtype=np.float32,
)

محاسبه لایه خطی:

bias = np.array(
    [
        0.1,
        -0.2,
    ],
    dtype=np.float32,
)

output = (
    batch @ weights
    + bias
)

این محاسبه شکل ساده‌ای از عملیات لایه Linear در شبکه عصبی است.

پیاده‌سازی Softmax با NumPy

def softmax(
    logits: np.ndarray,
) -> np.ndarray:
    logits = np.asarray(
        logits,
        dtype=np.float64,
    )

    shifted = (
        logits
        - np.max(
            logits,
            axis=-1,
            keepdims=True,
        )
    )

    exponentials = np.exp(
        shifted
    )

    return (
        exponentials
        / exponentials.sum(
            axis=-1,
            keepdims=True,
        )
    )

استفاده:

logits = np.array(
    [
        [2.0, 1.0, 0.1],
        [0.2, 0.3, 1.8],
    ]
)

probabilities = softmax(
    logits
)

print(probabilities)

کم‌کردن مقدار بیشینه پیش از exp به پایداری عددی کمک می‌کند.

پیاده‌سازی Sigmoid

def sigmoid(
    values: np.ndarray,
) -> np.ndarray:
    values = np.asarray(
        values,
        dtype=np.float64,
    )

    return 1.0 / (
        1.0
        + np.exp(-values)
    )

استفاده:

logits = np.array(
    [
        -2.0,
        0.0,
        2.0,
    ]
)

probabilities = sigmoid(
    logits
)

بهینه‌سازی حافظه

بررسی حافظه:

array = np.zeros(
    (
        1_000_000,
        128,
    ),
    dtype=np.float32,
)

print(
    array.nbytes
    / 1024**2
)

اگر float64 استفاده شود، حافظه تقریباً دو برابر خواهد شد:

float64_array = np.zeros(
    (
        1_000_000,
        128,
    ),
    dtype=np.float64,
)

برای Embedding معمولاً float32 نقطه شروع مناسبی است، اما تغییر dtype باید با اندازه‌گیری اثر آن بر دقت انجام شود.

استفاده از Memory Mapping

برای آرایه‌هایی که کامل در RAM جا نمی‌شوند:

shape = (
    1_000_000,
    128,
)

mapped = np.memmap(
    "embeddings.dat",
    dtype=np.float32,
    mode="w+",
    shape=shape,
)

نوشتن یک Batch:

mapped[
    0:1000
] = np.zeros(
    (
        1000,
        128,
    ),
    dtype=np.float32,
)

mapped.flush()

بازکردن مجدد:

mapped = np.memmap(
    "embeddings.dat",
    dtype=np.float32,
    mode="r",
    shape=shape,
)

Shape، dtype و Metadata فایل باید جداگانه ذخیره شوند؛ زیرا فایل خام Memmap به‌تنهایی آن‌ها را توضیح نمی‌دهد.

خطاهای رایج NumPy

خطای No module named 'numpy'

python -m pip install numpy

بررسی:

python -m pip show numpy

خطای ناسازگاری Shape

نمونه:

ValueError:
operands could not be broadcast together

Shapeها را چاپ کنید:

print(
    first.shape
)

print(
    second.shape
)

سپس بررسی کنید Dimensionهای آن‌ها از سمت راست با قوانین Broadcasting سازگار باشند.

خطای Reshape

ValueError:
cannot reshape array

تعداد Elementهای Shape جدید باید با array.size برابر باشد:

print(
    array.size
)

تغییر ناخواسته آرایه اصلی

احتمالاً یک View را تغییر داده‌اید:

subset = array[
    1:5
].copy()

خروجی nan

ورودی را بررسی کنید:

print(
    np.isnan(array).sum()
)

print(
    np.isinf(array).sum()
)

خطای Overflow

نوع داده ظرفیت کافی ندارد:

small = np.array(
    [
        120,
    ],
    dtype=np.int8,
)

پیش از محاسبه به نوع بزرگ‌تر تبدیل کنید:

safe = small.astype(
    np.int32
)

خطای نصب پس از ارتقای NumPy

بعضی کتابخانه‌های دارای بخش باینری ممکن است با نسخه جدید NumPy سازگار نباشند. ابتدا نسخه‌های کتابخانه‌ها و Dependencyها را بررسی و در یک Virtual Environment تمیز نصب کنید. راهنمای رسمی نیز در صفحه Troubleshooting نصب NumPy ارائه شده است.

اشتباهات متداول

استفاده از Loop برای تمام عملیات‌ها

ابتدا Broadcasting، Ufunc و عملیات Vectorized را بررسی کنید.

نادیده‌گرفتن dtype

انتخاب نامناسب dtype می‌تواند مصرف حافظه، دقت یا محدوده عددی را تغییر دهد.

اشتباه‌گرفتن ضرب Element-wise و Matrix Multiplication

a * b

با:

a @ b

متفاوت است.

تغییر View بدون اطلاع

Slicing معمولاً View ایجاد می‌کند. در صورت نیاز از .copy() استفاده کنید.

استفاده مستقیم از np.linalg.inv

برای حل دستگاه معادلات معمولاً np.linalg.solve مناسب‌تر است.

مقایسه Float با برابری دقیق

کد شکننده:

first == second

روش مناسب‌تر:

np.isclose(
    first,
    second,
)

برای آرایه:

np.allclose(
    first_array,
    second_array,
)

تولید عدد تصادفی بدون Generator

روش پیشنهادی:

rng = np.random.default_rng(
    42
)

نگهداری تمام داده در RAM

برای آرایه بزرگ، Memmap، Batch Processing، dtype کوچک‌تر یا ابزارهای مقیاس‌پذیرتر را بررسی کنید.

چک‌لیست استفاده از NumPy

  • Shape ورودی‌ها بررسی شده است.
  • dtype آگاهانه انتخاب شده است.
  • تفاوت View و Copy مشخص است.
  • عملیات تا حد ممکن Vectorized است.
  • Broadcasting قبل از اجرا بررسی شده است.
  • معنی axis در هر عملیات مشخص است.
  • NaN و Infinity کنترل می‌شوند.
  • تقسیم بر صفر مدیریت شده است.
  • Seed برای آزمایش‌های قابل‌بازتولید تنظیم شده است.
  • ضرب Element-wise و ماتریسی اشتباه نشده‌اند.
  • مصرف حافظه با nbytes بررسی شده است.
  • Model ID و Dimension بردارها ذخیره شده‌اند.
  • Embeddingهای مدل‌های مختلف مخلوط نشده‌اند.
  • نتیجه Similarity به‌عنوان اثبات قطعی تفسیر نمی‌شود.

سؤالات متداول

NumPy چیست؟

NumPy کتابخانه اصلی محاسبات عددی در Python است و ساختار ndarray را برای پردازش آرایه‌های چندبعدی ارائه می‌دهد.

ndarray چیست؟

ndarray آرایه چندبعدی NumPy است که معمولاً Elementهای هم‌نوع دارد و از عملیات Vectorized، Indexing و Broadcasting پشتیبانی می‌کند.

تفاوت NumPy و Pandas چیست؟

NumPy برای محاسبات آرایه‌ای و عددی طراحی شده است. Pandas ساختارهای دارای Label مانند DataFrame را برای تحلیل داده جدولی ارائه می‌دهد و در بسیاری از بخش‌ها از NumPy استفاده می‌کند.

آیا NumPy از GPU استفاده می‌کند؟

NumPy استاندارد معمولاً روی CPU اجرا می‌شود. برای محاسبات مشابه روی GPU می‌توان ابزارهایی مانند CuPy، PyTorch یا JAX را بررسی کرد.

آیا NumPy برای هوش مصنوعی ضروری است؟

اجباری نیست، اما درک NumPy یادگیری ساختار Tensor، عملیات ماتریسی، Normalization، Batch Processing و Embedding را بسیار ساده‌تر می‌کند.

Broadcasting در NumPy چیست؟

Broadcasting روشی است که NumPy برای اجرای عملیات روی آرایه‌هایی با Shape متفاوت اما سازگار استفاده می‌کند.

تفاوت reshape و resize چیست؟

reshape نمایی با Shape جدید از همان داده ایجاد می‌کند یا در صورت نیاز Copy می‌سازد. resize می‌تواند اندازه آرایه را تغییر دهد و رفتار متفاوتی دارد. برای تغییر Shape معمولاً reshape انتخاب واضح‌تری است.

تفاوت ravel و flatten چیست؟

flatten همیشه Copy ایجاد می‌کند. ravel در صورت امکان View برمی‌گرداند.

تفاوت np.dot و @ چیست؟

برای Vector و Matrix ساده، نتایج آن‌ها اغلب مشابه است؛ اما در آرایه‌های چندبعدی Semantics می‌تواند متفاوت باشد. برای Matrix Multiplication معمولاً @ یا np.matmul خواناتر است.

Cosine Similarity چیست؟

Cosine Similarity زاویه و هم‌جهتی دو بردار را اندازه می‌گیرد و در جست‌وجوی برداری و مقایسه Embeddingها استفاده می‌شود.

آیا NumPy جای Vector Database را می‌گیرد؟

برای Prototype و دیتاست کوچک می‌تواند کافی باشد. برای حجم بالا، فیلتر Metadata، آپدیت آنلاین و جست‌وجوی تقریبی، Vector Database گزینه مناسب‌تری است.

آیا می‌توان NumPy را با API درواره ترکیب کرد؟

بله. می‌توانید بردارها و نتایج عددی را با NumPy پردازش و خروجی بازیابی‌شده را برای تولید پاسخ یا گزارش به مدل‌های زبانی از طریق API درواره ارسال کنید.

جمع‌بندی

NumPy پایه محاسبات عددی در اکوسیستم علمی Python است. مفاهیمی مانند ndarray، Shape، dtype، Indexing، Broadcasting، Vectorization، View، Copy و Matrix Multiplication فقط امکانات یک کتابخانه نیستند؛ بلکه پایه درک بسیاری از عملیات یادگیری ماشین و هوش مصنوعی محسوب می‌شوند.

برای استفاده حرفه‌ای از NumPy، صرفاً یادگیری چند تابع کافی نیست. باید بتوانید Shape داده را در هر مرحله دنبال کنید، dtype مناسب انتخاب کنید، مصرف حافظه را اندازه بگیرید و تفاوت عملیات Element-wise با عملیات ماتریسی را تشخیص دهید.

پروژه جست‌وجوی برداری این مقاله نشان داد که با چند عملیات اصلی NumPy می‌توان بردارها را Normalize کرد، Cosine Similarity را برای تمام اسناد محاسبه کرد و مرتبط‌ترین نتایج را به دست آورد. همین مفاهیم در مقیاس بزرگ‌تر، بخش مهمی از Semantic Search و سیستم‌های RAG را تشکیل می‌دهند.

برای افزودن مدل‌های زبانی به پروژه‌های Python و هوش مصنوعی می‌توانید از API هوش مصنوعی درواره استفاده کنید. برای انتخاب Model ID و مشاهده قیمت‌های به‌روز نیز صفحه مدل‌ها و قیمت‌های درواره را ببینید.

مقالات مرتبط

برای مطالعه شرایط استفاده و محدودیت‌های مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.

Read more

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی با ترکیب گردش‌کارهای خودکار و مدل‌های هوش مصنوعی، پردازش متن، دسته‌بندی، استخراج اطلاعات و تصمیم‌های پیشنهادی را خودکار می‌کند. در این راهنما، معماری و ساخت نمونه عملی آن با API درواره را می‌آموزید.

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce شیوه‌ای جدید برای خرید اینترنتی است که در آن ایجنت هوش مصنوعی می‌تواند نیاز کاربر را بفهمد، محصولات را جست‌وجو و مقایسه کند و فرایند خرید را پیش ببرد. در این راهنما با معماری، UCP، ACP و پیاده‌سازی آن با API درواره آشنا می‌شوید.