Ниқобҳо ва филтркунӣ
Ин барои чӣ лозим аст
Дар таҳлили маълумот доимо интихоб кардан лозим меояд: «ҳамаи харидҳои аз 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) |