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

Ниқобҳо ва филтркунӣ

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

Дар таҳлили маълумот доимо интихоб кардан лозим меояд: «ҳамаи харидҳои аз 1000 гаронтар», «рӯзҳои бе боришот», «хонандагони баҳояшон аз миёна баланд», «нишондодҳои ҳисгар бе қиматҳои хато». Дар Python-и одӣ ин давра бо if дар дохил аст. Дар numpy барои ин ниқобҳо (mask) ҳастанд — массивҳо аз True ва False, ки нишон медиҳанд, кадом унсурҳо ба шарт мувофиқанд.

Бо ниқоб се кор кардан мумкин: унсурҳои мувофиқро интихоб кардан, шумораи онҳоро ҳисоб кардан ва онҳоро бо қиматҳои дигар иваз кардан. Ҳамааш — бе давраҳо ва бо як сатр. Дар ин мавзӯъ мебинем, ки ниқобҳо чӣ тавр сохта мешаванд, шартҳо чӣ тавр муттаҳид мешаванд ва функсияи np.where чӣ тавр кор мекунад.

Шарт болои массив — ниқоб

Муқоисаи массив бо адад унсур ба унсур иҷро мешавад, мисли арифметика. Натиҷа — массив аз True/False-и ҳамон шакл. Онро ниқоб (массиви мантиқӣ) меноманд.

import numpy as np

prices = np.array([120, 980, 45, 1500, 300])
mask = prices > 500
print(mask)
print(mask.dtype)

Натиҷа:

[False  True False  True False]
bool

Ҳамаи муқоисаҳо кор мекунанд: >, <, >=, <=, ==, !=. Ду массиви дарозиашон якхеларо ҳам муқоиса кардан мумкин:

import numpy as np

plan = np.array([100, 200, 150])
fact = np.array([120, 180, 150])
print(fact >= plan)
print(fact == plan)

Натиҷа:

[ True False  True]
[False False  True]

Интихоб бо ниқоб

Ниқобро ба қавсҳои мураббаъ гузоштан мумкин — танҳо унсурҳое мемонанд, ки дар онҳо True аст:

import numpy as np

prices = np.array([120, 980, 45, 1500, 300])
print(prices[prices > 500])
print(prices[prices < 100])
print(prices[prices > 5000])

Натиҷа:

[ 980 1500]
[45]
[]

Агар ягон унсур мувофиқ наояд, массиви холӣ ҳосил мешавад — на хато. Одатан ниқобро ба тағйирёбанда нигоҳ намедоранд, балки шартро бевосита дар қавс менависанд: prices[prices > 500] чунин хонда мешавад: «нархҳое, ки нарх аз 500 зиёд аст».

Ниқоби як массивро ба массиви дигари ҳамон дарозӣ татбиқ кардан мумкин. Масалан, номи молҳое, ки аз 500 гаронтаранд:

import numpy as np

names = np.array(["қалам", "гӯшмонак", "поккунак", "курсӣ", "чароғ"])
prices = np.array([120, 980, 45, 1500, 300])
print(names[prices > 500])

Натиҷа:

['гӯшмонак' 'курсӣ']

Бо ҷадвалҳо ҳам ниқоб кор мекунад: m[m > 0] массиви якченака-и ҳамаи унсурҳои мусбатро бармегардонад (сатрҳо ва сутунҳо гум мешаванд).

import numpy as np

m = np.array([[3, -1],
              [-4, 5]])
print(m[m > 0])

Натиҷа:

[3 5]

Чандто мувофиқ аст: ҳисобкунӣ бо ниқоб

Дар ҳисобҳо True ҳамчун 1, False бошад ҳамчун 0 ҳисоб мешавад. Аз ин усулҳои қулай пайдо мешаванд:

import numpy as np

prices = np.array([120, 980, 45, 1500, 300])
print((prices > 500).sum())
print((prices > 500).mean())
print(np.count_nonzero(prices > 500))

Натиҷа:

2
0.4
2
  • .sum()-и ниқоб — чандто унсур мувофиқанд;
  • .mean()-и ниқоб — ҳиссаи мувофиқҳо (дар ин ҷо 2 аз 5 = 0.4);
  • np.count_nonzero — ҳамон .sum().

any() ва all() барои санҷидани «оё ақаллан яке мувофиқ аст» ва «оё ҳама мувофиқанд» кӯмак мекунанд:

import numpy as np

prices = np.array([120, 980, 45, 1500, 300])
print((prices > 2000).any())
print((prices > 0).all())

Натиҷа:

False
True

Шумораи мувофиқҳоро инчунин тавассути size-и массиви интихобшуда донистан мумкин: prices[prices > 500].size. Ин вақте қулай аст, ки унсурҳои интихобшуда минбаъд ҳам лозиманд — масалан, барои ҳисоб кардани миёнаи онҳо.

Якчанд шарт: &, |, ~

Шартҳоро бо амалгарҳои махсус муттаҳид мекунанд:

Амалгар Маъно
& ва — ҳарду шарт дурустанд
| ё — ақаллан яке дуруст аст
~ не — ниқобро баръакс мекунад

Ҳар шарт ҳатман дар қавс гирифта мешавад: & ва | аз муқоисаҳо афзалияти баландтар доранд ва бе қавс Python навиштро нодуруст мефаҳмад.

import numpy as np

prices = np.array([120, 980, 45, 1500, 300])
middle = (prices >= 100) & (prices <= 1000)
print(prices[middle])
print(prices[(prices < 100) | (prices > 1000)])
print(prices[~middle])

Натиҷа:

[120 980 300]
[  45 1500]
[  45 1500]

and, or, not-и одӣ бо массивҳо кор намекунанд: онҳо як қимати True ё False-ро интизоранд, вале тамоми массивро мегиранд. Дар ин бора — дар қисми хатоҳо.

Тағйир додан бо ниқоб

Бо ниқоб навиштан ҳам мумкин — қимат ба ҳамаи катакҳои мувофиқ навишта мешавад:

import numpy as np

temps = np.array([12, -999, 15, -999, 14])
temps[temps == -999] = 0
print(temps)

Натиҷа:

[12  0 15  0 14]

Дар ин ҷо -999 — рамзи шартии «ҳисгар кор накард» аст ва мо онро бо сифр иваз кардем. Дар тарафи рост массиви дарозиаш мувофиқро ҳам гузоштан мумкин — он гоҳ қиматҳо бо тартиб навишта мешаванд:

import numpy as np

a = np.array([5, -1, 7, -3])
a[a < 0] = a[a < 0] * 10
print(a)

Натиҷа:

[  5 -10   7 -30]

Чунин навиштан массиви аслиро тағйир медиҳад. Агар он ҳанӯз лозим бошад, аввал нусха созед: b = a.copy().

np.where — «агар — он гоҳ — вагарна»

np.where(шарт, x, y) массиви нав месозад: дар ҷое, ки шарт дуруст аст, қиматро аз x, вагарна аз y мегирад. Дар ҷои x ва y ададҳо ё массивҳои ҳамон шакл буда метавонанд.

import numpy as np

scores = np.array([45, 72, 38, 90])
print(np.where(scores >= 50, "қабул", "рад"))
print(np.where(scores > 80, scores + 5, scores))
print(np.where(scores < 50, 0, 1))

Натиҷа:

['рад' 'қабул' 'рад' 'қабул']
[45 72 38 95]
[0 1 0 1]

Барои зиёда аз ду вариант np.where-ро ба ҳамдигар ҷой медиҳанд — мисли if … elif … else:

import numpy as np

t = np.array([-5, 10, 25, 32])
print(np.where(t < 0, "сармо", np.where(t < 20, "салқин", "гарм")))

Натиҷа:

['сармо' 'салқин' 'гарм' 'гарм']

Маҳдуд кардани қиматҳо: np.clip

Ҳолати маъмул — «ҳар чизи аз low хурдро бо low, ҳар чизи аз high калонро бо high иваз кардан». Барои ин функсияи тайёр ҳаст:

import numpy as np

x = np.array([-3, 5, 12, 8])
print(np.clip(x, 0, 10))

Натиҷа:

[ 0  5 10  8]

Индексҳои унсурҳои мувофиқ

Бо як аргумент np.where(шарт) на қиматҳо, балки индексҳои унсурҳои мувофиқро бармегардонад. Натиҷа — кортеж бо як массиви индексҳо барои ҳар меҳвар, бинобар ин дар массиви якченака унсури [0]-ро мегиранд:

import numpy as np

scores = np.array([45, 72, 38, 90])
print(np.where(scores > 50)[0])

Натиҷа:

[1 3]

np.flatnonzero(scores > 50) ҳамонро дарҳол ҳамчун массив медиҳад.

Ниқобҳо дар ҷадвалҳо ва меҳварҳо

Ниқобҳо бо агрегатҳо аз рӯи меҳварҳо хуб якҷоя мешаванд. Бигзор сатрҳо — мағозаҳо, сутунҳо — рӯзҳо бошанд:

import numpy as np

sales = np.array([[5, 0, 8],
                  [0, 0, 4]])
print((sales > 0).sum(axis=1))
print((sales == 0).any(axis=0))
print((sales > 0).all(axis=0))

Натиҷа:

[2 1]
[ True  True False]
[False False  True]
  • сатри якум: ҳар мағоза чанд рӯз фурӯш дошт;
  • дуюм: дар кадом рӯзҳо касе ҳеҷ чиз нафурӯхт;
  • сеюм: дар кадом рӯзҳо ҳама фурӯхтанд.

Бо массиви-сатр ҳам муқоиса кардан мумкин: m > np.array([2, 6]) сутуни якумро бо 2, дуюмро бо 6 муқоиса мекунад (ин broadcasting аз мавзӯи гузашта аст).

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

Ниқоб — массиви одии numpy бо навъи bool аст, барои ҳар унсур як байт. Вақте шумо a[mask] менависед, numpy аз болои ниқоб мегузарад ва ба массиви нав унсурҳои a-ро нусха мекунад, ки муқобилашон True аст. Бинобар ин натиҷаи интихоб бо ниқоб ҳамеша нусха аст ва дарозии онро пешакӣ касе намедонад — он ба шумораи True баробар аст.

Навиштани a[mask] = 0 баръакс кор мекунад: numpy аз болои ниқоб мегузарад ва сифрро бевосита ба массиви аслӣ менависад.

Монандӣ: ниқоб — трафарет бо сӯрохиҳост. Онро болои қатори ададҳо гузоштед — танҳо ададҳои зери сӯрохиҳоро мебинед. Онҳоро ба дафтар нусха кардан (интихоб) ё бевосита аз трафарет ранг кардан (навиштан) мумкин.

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

1. Ба ҷои &/| — and/or.

# хато: and бо массивҳо
import numpy as np
a = np.array([1, 5, 9])
print(a[(a > 2) and (a < 8)])

Натиҷа:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Ислоҳ: a[(a > 2) & (a < 8)]. Муқоисаи дукаратаи 2 < a < 8 ҳамон хаторо медиҳад.

2. Қавсҳоро дар атрофи шартҳо фаромӯш кардан. a > 2 & a < 8-ро Python ҳамчун a > (2 & a) < 8 мехонад ва боз хато медиҳад. Қоида содда аст: ҳар шарт — дар қавсҳои худ.

3. if бо массив. Сохтори if a > 5: бо ҳамон сабаб кор намекунад: маълум нест, ки бо массиви бисёр True/False чӣ бояд кард. Ошкоро гуфтан лозим: if (a > 5).any(): — «ақаллан яке», ё if (a > 5).all(): — «ҳама».

4. Миёнаи интихоби холӣ. Агар ягон унсур мувофиқ наояд, mean()-и массиви холӣ nan ва огоҳӣ медиҳад:

import numpy as np

a = np.array([1, 2, 3])
good = a[a > 10]
print(good.size)
print(good.mean())

Натиҷа:

0
nan

Ислоҳ: аввал андозаро санҷед (if good.size:), баъд ҳисоб кунед.

5. Интизор шудан, ки np.where массивро тағйир медиҳад. np.where ҳамеша массиви нав бармегардонад. Натиҷаро нигоҳ доштан лозим: a = np.where(a < 0, 0, a).

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

Чӣ лозим Чӣ тавр навиштан
ниқоб a > 5, a == 0, a != b
интихоб аз рӯи шарт a[a > 5]
интихоб дар массиви дигар names[prices > 500]
чандто мувофиқ (a > 5).sum()
ҳиссаи мувофиқҳо (a > 5).mean()
оё ҳаст / оё ҳама (a > 5).any(), (a > 5).all()
ва / ё / не (a > 2) & (a < 8), (a < 2) | (a > 8), ~mask
иваз кардани мувофиқҳо a[a < 0] = 0
агар — он гоҳ — вагарна np.where(a < 0, 0, a)
маҳдуд кардан аз поён ва боло np.clip(a, low, high)
индексҳои мувофиқҳо np.where(a > 5)[0], np.flatnonzero(a > 5)
аз рӯи сатрҳо / сутунҳо (m > 0).sum(axis=1), (m == 0).any(axis=0)