Масивът на NumPy
Накратко: Масивът на NumPy (ndarray) пази числа от един тип (dtype) с форма (shape) и смята с тях много по-бързо от списък в Python.
Проблем
„Сложи ДДС на всички цени“
Магазинът има 25 продукта. Управителят иска цените с ДДС: всяка цена по 1,2. След това иска година продажби по дни: 25 продукта по 365 дни, тоест 9 125 числа.
Числата в Python досега са били в списък. Само че списъкът не смята:
* 2 не удвоява цените, а повтаря списъка два пъти. * 1.2 е грешка. Остава цикъл for за всяка сметка, а с 9 125 числа, после с милион, кодът става дълъг и бавен.
Идеята
Масив: един блок от числа
Списъкът е сбор от отделни обекти. Във всяка негова клетка стои адрес, а самото число е другаде в паметта, със своя „опаковка“ на Python. Затова списъкът може да държи каквото и да е: число, текст, друг списък.
Анализът на данни не иска това. Той иска много числа от един и същи тип. NumPy е библиотеката за това, а основното ѝ нещо е масивът (array): числата са едно до друго в един блок памет, всичките от един тип. Ето милион цени като списък и като масив:
Списъкът заема 20,2 MB, а масивът 8,0 MB: по 8 байта на цена и нищо повече. Пясъчникът е 32-битов. На обикновен 64-битов компютър адресите и опаковките са по-големи и списъкът става около 32 MB, а масивът си остава 8 MB.
Блокът от еднакви числа се обработва и по-бързо: NumPy минава през него с готов код на C, без да пита за типа на всяко число. Ето ДДС-то на милион цени:
array * 1.2 умножава всички цени наведнъж. В пясъчника масивът е няколко пъти по-бърз от цикъла. На обикновен компютър разликата е десетки пъти. Точното време зависи от машината, затова кодът казва само кое е по-бързо.
По-точно, за любопитните
import numpy as np е навикът на всички, както pd за pandas. Самият pandas е построен върху NumPy: колоната на таблицата пази числата си в масив. Затова наученото тук важи и за таблиците.
Идеята
Масив от таблицата: dtype
Цените вече са в products.csv. to_numpy() взима колоната от таблицата като масив. Всеки масив знае типа на числата си: това е dtype.
prices[:5] дава първите пет, както при списък. Масивът се печата без запетаи: [1.2 1.9 0.8 2.5 1.6].
float64: дробни числа, по 8 байта (64 бита). Такива са цените.int64: цели числа, също по 8 байта. Такава е наличността.
Виж го
Когато типовете се смесят
Типът е един за целия масив. Какво става, ако сложиш различни неща в него?
- Цели и дробни: всички стават дробни.
40става40.0без загуба, а обратното би отрязало 1,5. - Едно парче текст: всичко става текст.
<U32значи низ до 32 знака. Числата вече не са числа.
По-точно, за любопитните
Ако напишеш np.array([40, 25, 60]) в пясъчника, типът ще е int32, а не int64. Цялото число по подразбиране следва машината, а пясъчникът е 32-битов. На компютъра ти е int64. Колоните, прочетени с pandas, са int64 и тук. За бройки в магазин двата типа стигат: int32 държи числа до около 2,1 милиарда.
Идеята
Форма: shape и ndim
Цените са един ред числа. Продажбите по седмици са таблица: ред за всеки продукт, колона за всяка седмица. Масивът може да е и двете.
shapeе формата: колко числа има по всяка посока.ndimе броят на посоките (измеренията).
Цените са с форма (25,): едно измерение с 25 числа. Запетаята е там, защото формата винаги е двойка, тройка и т.н. (кортеж), дори с едно число в нея. Таблицата е (3, 4): 3 реда (продуктите) и 4 колони (седмиците). Първо са редовете, после колоните, както при shape в pandas.
Пробвай
Продукти и седмици
В qty има бройки по продукт (редове) и по седмица (колони). Запиши в n_products броя на продуктите, а в n_weeks броя на седмиците, взети от формата на масива.
Решение
import numpy as np
qty = np.array([
[4, 2, 5, 3],
[1, 0, 2, 2],
[6, 7, 5, 8],
])
n_products = qty.shape[0]
n_weeks = qty.shape[1]qty.shape е (3, 4), затова n_products = qty.shape[0] (3) и n_weeks = qty.shape[1] (4). len(qty) дава само броя на редовете, а qty.size броя на всички числа: 12.
Идеята
Готови масиви: arange и zeros
Често масивът не идва от файл, а го правиш сам:
np.arange(начало, край)дава поредни числа, катоrange. Краят не влиза.np.zeros(форма)дава масив от нули. Удобен е за таблица, която ще попълваш. Формата на таблица е двойка:np.zeros((редове, колони)), с двойни скоби.
Дните са от 1 до 365, затова краят е 366. Таблицата за година продажби е (25, 365): 9 125 нули от тип float64, готови за числата.
Упражнение
Ценоразписът и годината
Направи days с дните от 1 до 365 и sales: таблица от нули с ред за всеки от 25-те продукта и колона за всеки ден.
Решение
import numpy as np
days = np.arange(1, 366)
sales = np.zeros((25, 365))days = np.arange(1, 366): краят 366 не влиза, затова последният ден е 365. np.arange(365) започва от 0. sales = np.zeros((25, 365)): първо редовете (продуктите), после колоните (дните). np.zeros((365, 25)) също е таблица, но обърната.
Сложи цените и наличностите в един масив table с два реда: първият с цените, вторият с наличностите. Запиши в kind типа на table.
Решение
import numpy as np
import pandas as pd
products = pd.read_csv('products.csv')
prices = products['price'].to_numpy()
stock = products['stock'].to_numpy()
table = np.array([prices, stock])
kind = table.dtypetable = np.array([prices, stock]) е с форма (2, 25). Типът е float64, макар че наличностите бяха int64: в един масив всичко е от един тип, а цените са дробни. Затова наличността 40 вече се показва като 40.0.
Тест
Провери се
Свързани уроци
Раздел „Свързани уроци“- Нужно отпреди: Първата таблица
- Продължава в: Векторизация · Обобщения и липсващи стойности · Broadcasting: числото, редът и колоната · Series и DataFrame
- Задачи по темата: NumPy