Към съдържанието
wannacode

Масивът на NumPy

Накратко: Масивът на NumPy (ndarray) пази числа от един тип (dtype) с форма (shape) и смята с тях много по-бързо от списък в Python.

Проблем

„Сложи ДДС на всички цени“

Магазинът има 25 продукта. Управителят иска цените с ДДС: всяка цена по 1,2. След това иска година продажби по дни: 25 продукта по 365 дни, тоест 9 125 числа.

Числата в Python досега са били в списък. Само че списъкът не смята:

Pythonданни: таблиците на магазина

* 2 не удвоява цените, а повтаря списъка два пъти. * 1.2 е грешка. Остава цикъл for за всяка сметка, а с 9 125 числа, после с милион, кодът става дълъг и бавен.

Идеята

Масив: един блок от числа

Списъкът е сбор от отделни обекти. Във всяка негова клетка стои адрес, а самото число е другаде в паметта, със своя „опаковка“ на Python. Затова списъкът може да държи каквото и да е: число, текст, друг списък.

Анализът на данни не иска това. Той иска много числа от един и същи тип. NumPy е библиотеката за това, а основното ѝ нещо е масивът (array): числата са едно до друго в един блок памет, всичките от един тип. Ето милион цени като списък и като масив:

Pythonданни: таблиците на магазина

Списъкът заема 20,2 MB, а масивът 8,0 MB: по 8 байта на цена и нищо повече. Пясъчникът е 32-битов. На обикновен 64-битов компютър адресите и опаковките са по-големи и списъкът става около 32 MB, а масивът си остава 8 MB.

Блокът от еднакви числа се обработва и по-бързо: NumPy минава през него с готов код на C, без да пита за типа на всяко число. Ето ДДС-то на милион цени:

Pythonданни: таблиците на магазина

array * 1.2 умножава всички цени наведнъж. В пясъчника масивът е няколко пъти по-бърз от цикъла. На обикновен компютър разликата е десетки пъти. Точното време зависи от машината, затова кодът казва само кое е по-бързо.

По-точно, за любопитните

import numpy as np е навикът на всички, както pd за pandas. Самият pandas е построен върху NumPy: колоната на таблицата пази числата си в масив. Затова наученото тук важи и за таблиците.

Идеята

Масив от таблицата: dtype

Цените вече са в products.csv. to_numpy() взима колоната от таблицата като масив. Всеки масив знае типа на числата си: това е dtype.

Pythonданни: таблиците на магазина

prices[:5] дава първите пет, както при списък. Масивът се печата без запетаи: [1.2 1.9 0.8 2.5 1.6].

  • float64: дробни числа, по 8 байта (64 бита). Такива са цените.
  • int64: цели числа, също по 8 байта. Такава е наличността.

Виж го

Когато типовете се смесят

Типът е един за целия масив. Какво става, ако сложиш различни неща в него?

Pythonданни: таблиците на магазина
  • Цели и дробни: всички стават дробни. 40 става 40.0 без загуба, а обратното би отрязало 1,5.
  • Едно парче текст: всичко става текст. <U32 значи низ до 32 знака. Числата вече не са числа.
1. Какво дава np.array([1.2, 1.9, '0.8']) * 2?
По-точно, за любопитните

Ако напишеш np.array([40, 25, 60]) в пясъчника, типът ще е int32, а не int64. Цялото число по подразбиране следва машината, а пясъчникът е 32-битов. На компютъра ти е int64. Колоните, прочетени с pandas, са int64 и тук. За бройки в магазин двата типа стигат: int32 държи числа до около 2,1 милиарда.

Идеята

Форма: shape и ndim

Цените са един ред числа. Продажбите по седмици са таблица: ред за всеки продукт, колона за всяка седмица. Масивът може да е и двете.

  • shape е формата: колко числа има по всяка посока.
  • ndim е броят на посоките (измеренията).
Pythonданни: таблиците на магазина

Цените са с форма (25,): едно измерение с 25 числа. Запетаята е там, защото формата винаги е двойка, тройка и т.н. (кортеж), дори с едно число в нея. Таблицата е (3, 4): 3 реда (продуктите) и 4 колони (седмиците). Първо са редовете, после колоните, както при shape в pandas.

Пробвай

Продукти и седмици

В qty има бройки по продукт (редове) и по седмица (колони). Запиши в n_products броя на продуктите, а в n_weeks броя на седмиците, взети от формата на масива.

Pythonданни: таблиците на магазина

Идеята

Готови масиви: arange и zeros

Често масивът не идва от файл, а го правиш сам:

  • np.arange(начало, край) дава поредни числа, като range. Краят не влиза.
  • np.zeros(форма) дава масив от нули. Удобен е за таблица, която ще попълваш. Формата на таблица е двойка: np.zeros((редове, колони)), с двойни скоби.
Pythonданни: таблиците на магазина

Дните са от 1 до 365, затова краят е 366. Таблицата за година продажби е (25, 365): 9 125 нули от тип float64, готови за числата.

Упражнение

Ценоразписът и годината

Направи days с дните от 1 до 365 и sales: таблица от нули с ред за всеки от 25-те продукта и колона за всеки ден.

Pythonданни: таблиците на магазина

Сложи цените и наличностите в един масив table с два реда: първият с цените, вторият с наличностите. Запиши в kind типа на table.

Pythonданни: таблиците на магазина

Тест

Провери се

1. Защо масив от милион цени заема по-малко памет от списък със същите цени?
2. Какъв е dtype на np.array([40, 25, 1.5])?
3. Продажбите на 25 продукта за 7 дни са в масив с ред за всеки продукт. Какво е sales.shape?
4. Кои дни дава np.arange(1, 8)?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·