Гузариш ба мундариҷа
Мавзӯи 5 аз 6

Шакли массивҳо

Ин барои чӣ лозим аст

Ҳамон ададҳоро бо роҳҳои гуногун ҷойгир кардан мумкин: дар як қатори дароз, дар ҷадвали 3×4 ё 4×3, ҷадвалро «ба паҳлӯ» гардондан, бо ҷадвали дигар пайвастан. Масалан, нишондодҳои ҳисгар дар як шабонарӯз ҳамчун қатори яклухти 24 адад меоянд, вале барои таҳлил ҷадвали «6 ченкунӣ × 4 соат» қулайтар аст. Ё ҳисоботи ду шӯъбаро ба як ҷадвал ҷамъ кардан лозим.

Дар ин мавзӯъ — абзорҳое, ки шакли массивро бе тағйир додани худи ададҳо иваз мекунанд: reshape, ravel, транспонкунии .T, илова кардани меҳвари нав, пайвастан бо concatenate ва stack, такрор бо repeat ва tile.

Шакли массив — ёдоварӣ

Шакл (shape) — кортеж бо андозаҳо аз рӯи ҳар меҳвар. Массиви якченака аз 12 адад шакли (12,), ҷадвали 3 сатр ва 4 сутун — (3, 4) дорад. Ҳосили зарби андозаҳо ҳамеша ба шумораи унсурҳо size баробар аст.

import numpy as np

a = np.arange(12)
print(a.shape, a.size)
m = a.reshape(3, 4)
print(m.shape, m.size)

Натиҷа:

(12,) 12
(3, 4) 12

reshape — шакли нав

reshape ҳамон унсурҳоро аз рӯи шакли нав ҷойгир мекунад. Унсурҳо ҷадвалро сатр ба сатр пур мекунанд: аввал сатри якум аз чап ба рост, баъд дуюм ва ғайра.

import numpy as np

a = np.arange(12)
print(a.reshape(3, 4))
print(a.reshape(4, 3))

Натиҷа:

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

Яке аз андозаҳоро худатон ҳисоб накарда, -1 навиштан мумкин — numpy онро аз шумораи унсурҳо ҳисоб мекунад:

import numpy as np

a = np.arange(12)
print(a.reshape(2, -1).shape)
print(a.reshape(-1, 6).shape)
print(a.reshape(-1).shape)

Натиҷа:

(2, 6)
(2, 6)
(12,)

-1 танҳо як буда метавонад: агар ду андоза номаълум бошад, онҳоро ҳисоб кардан мумкин нест.

reshape-ро ба ҷадвал ҳам татбиқ кардан мумкин — numpy аввал онро ба таври фикрӣ сатр ба сатр ба як қатор «дароз мекунад», баъд аз нав ҷойгир мекунад:

import numpy as np

m = np.array([[1, 2, 3],
              [4, 5, 6]])
print(m.reshape(3, 2))

Натиҷа:

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

Диққат диҳед: ин гардондани ҷадвал нест. Ададҳо бо ҳамон тартиби 1 2 3 4 5 6 меоянд, танҳо сатрҳо кӯтоҳтар шуданд. Гардондан — ин транспонкунӣ аст, дар бораи он дар поён.

Бозгашт ба қатор: ravel ва flatten

Барои ба як қатор дароз кардани ҷадвал ду усул ҳаст:

import numpy as np

m = np.array([[1, 2],
              [3, 4]])
print(m.ravel())
print(m.flatten())

Натиҷа:

[1 2 3 4]
[1 2 3 4]

Ҳарду ҷадвалро сатр ба сатр мехонанд. Фарқ дар дохил: flatten ҳамеша нусха месозад, ravel бошад агар имкон бошад тиреза ба ҳамон маълумотро бармегардонад (тезтар, вале тағйирот дар он дар ҷадвали аслӣ намоён мешаванд).

Дароз кардан, масалан, барои чопи ҳамаи ададҳои ҷадвал дар як сатр қулай аст: print(*m.ravel()).

Транспонкунӣ: .T

Транспонкунӣ сатрҳо ва сутунҳоро ҷой иваз мекунад: унсур аз сатри i ва сутуни j ба сатри j ва сутуни i мегузарад. Сатри якум сутуни якум мешавад.

import numpy as np

m = np.array([[1, 2, 3],
              [4, 5, 6]])
print(m.T)
print(m.shape, m.T.shape)
print(m.T[0])

Натиҷа:

[[1 4]
 [2 5]
 [3 6]]
(2, 3) (3, 2)
[1 4]

Транспонкунӣ вақте лозим аст, ки маълумот «аз тарафи нодуруст» навишта шудааст. Масалан, дар ҷадвал сатрҳо — хонандагон, сутунҳо — фанҳо ва шумо мехоҳед фанҳоро бо давраи for гузаред: давра аз болои m.T аз рӯи сутунҳои ҷадвали аслӣ меравад.

import numpy as np

grades = np.array([[5, 4],
                   [3, 5],
                   [4, 4]])
for subject in grades.T:
    print(*subject)

Натиҷа:

5 3 4
4 5 4

Дар массиви якченака .T ҳеҷ чизро тағйир намедиҳад: вай танҳо як меҳвар дорад.

Меҳвари нав: сатр ва сутун

Баъзан массиви якченакаро ба ҷадвали як сатр ё як сутун табдил додан лозим — масалан, барои broadcasting ё пайвастан. Инро бо reshape ва -1 ё бо None дар индекс мекунанд:

import numpy as np

a = np.array([1, 2, 3])
print(a.reshape(1, -1))
print(a.reshape(-1, 1))
print(a[:, None].shape, a[None, :].shape)

Натиҷа:

[[1 2 3]]
[[1]
 [2]
 [3]]
(3, 1) (1, 3)

a[:, None] чунин хонда мешавад: «ҳамаи унсурҳо ва меҳвари навро ҳамчун андозаи дуюм илова кун». Ба ҷои None np.newaxis навиштан мумкин — ин ҳамон аст.

Пайвастан: concatenate

np.concatenate массивҳоро бар тӯли меҳвари мавҷуда мепайвандад. Массивҳо ҳамчун рӯйхат дода мешаванд.

import numpy as np

a = np.array([1, 2])
b = np.array([3, 4, 5])
print(np.concatenate([a, b]))

Натиҷа:

[1 2 3 4 5]

Дар ҷадвалҳо меҳварро бо параметри axis интихоб мекунанд:

  • axis=0 — ҷадвали дуюм ба поён илова мешавад; шумораи сутунҳо бояд мувофиқ ояд;
  • axis=1 — ба рост; шумораи сатрҳо бояд мувофиқ ояд.
import numpy as np

top = np.array([[1, 2],
                [3, 4]])
bottom = np.array([[5, 6]])
right = np.array([[7],
                  [8]])
print(np.concatenate([top, bottom], axis=0))
print(np.concatenate([top, right], axis=1))

Натиҷа:

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

Пешакӣ санҷидан, ки пайвастан мешавад ё не, аз рӯи шаклҳо мумкин: барои ҷадвалҳои (n1, m1) ва (n2, m2) ҳангоми пайвастан ба поён m1 == m2, ба рост — n1 == n2 лозим.

Синонимҳои кӯтоҳ: np.vstack([a, b]) («vertical» — ба поён) ва np.hstack([a, b]) («horizontal» — ба рост).

import numpy as np

a = np.array([[1, 2]])
b = np.array([[3, 4]])
print(np.vstack([a, b]))
print(np.hstack([a, b]))

Натиҷа:

[[1 2]
 [3 4]]
[[1 2 3 4]]

Пайвастан бо меҳвари нав: stack

np.stack массивҳои шаклашон якхела-ро бо илова кардани меҳвари нав мепайвандад. Аз якчанд сатр ҷадвал ҳосил мешавад:

import numpy as np

x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
print(np.stack([x, y]))
print(np.stack([x, y], axis=1))
print(np.stack([x, y]).shape, np.concatenate([x, y]).shape)

Натиҷа:

[[1 2 3]
 [4 5 6]]
[[1 4]
 [2 5]
 [3 6]]
(2, 3) (6,)

Фарқ: concatenate массивро идома медиҳад (3 + 3 буд, 6 дар як қатор шуд), stack бошад массивҳоро болои ҳам мегузорад (2 сатр аз 3 шуд). Бо axis=1 массивҳо сутунҳо мешаванд — барои ҷамъ кардани ҷадвал аз якчанд аломат қулай аст.

Такрор: repeat ва tile

import numpy as np

print(np.repeat([1, 2], 3))
print(np.tile([1, 2], 3))

Натиҷа:

[1 1 1 2 2 2]
[1 2 1 2 1 2]
  • np.repeat(a, k) ҳар унсурро k маротиба паи ҳам такрор мекунад;
  • np.tile(a, k) тамоми массивро k маротиба такрор мекунад.

tile метавонад ҷадвалро бо блокҳо, мисли сафолак, гузорад: np.tile(a, (p, q)) — p маротиба ба поён ва q маротиба ба рост.

import numpy as np

block = np.array([[1, 2],
                  [3, 4]])
print(np.tile(block, (2, 3)))

Натиҷа:

[[1 2 1 2 1 2]
 [3 4 3 4 3 4]
 [1 2 1 2 1 2]
 [3 4 3 4 3 4]]

Шакли натиҷа — (2·2, 2·3) = (4, 6).

Дар дохил чӣ тавр кор мекунад

Массиви numpy — қатори яклухти ададҳо дар хотира ва «шиноснома» аст: шакл ва қадамҳо (strides) — чанд байт ҷой иваз кардан лозим, то ба унсури навбатӣ аз рӯи ҳар меҳвар гузарем. reshape ва .T одатан ададҳоро интиқол намедиҳанд, балки танҳо шиносномаи нав менависанд. Масалан, ҷадвали (2, 3) аз int32 қадамҳои (12, 4) дорад: сатри навбатӣ — пас аз 12 байт, сутуни навбатӣ — пас аз 4. Дар ҷадвали транспоншуда қадамҳо баръакс (4, 12) мебошанд. Бинобар ин .T ҳатто барои ҷадвалҳои азим фавран кор мекунад.

import numpy as np

m = np.arange(6, dtype=np.int32).reshape(2, 3)
print(m.strides, m.T.strides)

Натиҷа:

(12, 4) (4, 12)

Пайвастан (concatenate, stack) ва такрор (repeat, tile) ин тавр карда наметавонанд: онҳо массиви нав месозанд ва ададҳоро ба он нусха мекунанд.

Хатоҳои маъмул

1. Шумораи унсурҳо ба шакли нав мувофиқ нест.

# хато: 12 унсурро ба 5×2 ҷойгир кардан мумкин нест
import numpy as np
print(np.arange(12).reshape(5, 2))

Натиҷа:

ValueError: cannot reshape array of size 12 into shape (5,2)

2. Фикр кардан, ки reshape ҷадвалро мегардонад. m.reshape(3, 2) дар ҷадвали 2×3 ба m.T баробар нест: ададҳо бо тартиби пешина меоянд. Гардондан лозим бошад — .T-ро истифода баред.

3. Ҷадвалҳоро бо шумораи гуногуни сутунҳо ба поён пайвастан.

# хато: ҷадвалҳо 2 ва 3 сутун доранд
import numpy as np
a = np.zeros((2, 2))
b = np.zeros((1, 3))
print(np.concatenate([a, b], axis=0))

Натиҷа:

ValueError: all the input array dimensions except for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 2 and the array at index 1 has size 3

Пеш аз пайвастан шаклҳоро муқоиса кунед: a.shape[1] == b.shape[1] барои пайвастан ба поён, a.shape[0] == b.shape[0] — ба рост.

4. Массивҳоро на ҳамчун рӯйхат додан. np.concatenate(a, b) — хато: аргументи дуюми функсия меҳвар аст. Дуруст: np.concatenate([a, b]).

5. repeat ва tile-ро омехтан. repeat — «ҳар унсур k маротиба» (1 1 2 2), tile — «тамоми массив k маротиба» (1 2 1 2).

Ёддошти кӯтоҳ

Чӣ лозим Чӣ тавр навиштан
шакли нав a.reshape(n, m), як андоза метавонад -1 бошад
ба қатор дароз кардан m.ravel() (тиреза), m.flatten() (нусха)
сатрҳо ва сутунҳоро ҷой иваз кардан m.T
сатр / сутун аз массив a.reshape(1, -1), a.reshape(-1, 1), a[:, None]
паи ҳам пайвастан np.concatenate([a, b])
ба поён илова кардан np.concatenate([a, b], axis=0) ё np.vstack
ба рост илова кардан np.concatenate([a, b], axis=1) ё np.hstack
ба ҷадвал гузоштан (меҳвари нав) np.stack([x, y]), ҳамчун сутунҳо — axis=1
ҳар унсур k маротиба np.repeat(a, k)
тамоми массив k маротиба np.tile(a, k)
сафолак p × q np.tile(a, (p, q))