Как уменьшить размерность массива python
Перейти к содержимому

Как уменьшить размерность массива python

  • автор:

Как изменить размер массива обрезав ненужные данные?

Конечно же можно использовать транспонирование через zip :

from pprint import pprint arr = [[0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 3,5, 6, 7,0, 0, 0], [0, 1, 1,1, 1, 1,7, 0, 0], [0, 7, 1,1, 1, 1,1, 7, 0], [0, 7, 1,1, 1, 1,1, 7, 0], [0, 7, 1,1, 1, 1,7, 0, 0], [0, 0, 7,7, 7, 7,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0]] pprint(list(zip(*filter(any, zip(*filter(any, arr)))))) # [(0, 3, 5, 6, 7, 0, 0), # (1, 1, 1, 1, 1, 7, 0), # (7, 1, 1, 1, 1, 1, 7), # (7, 1, 1, 1, 1, 1, 7), # (7, 1, 1, 1, 1, 7, 0), # (0, 7, 7, 7, 7, 0, 0)] 
  1. filter(any, arr) — отсеиваем строки, состоящие из нулей
  2. zip(*filter(any, arr)) — транспонируем матрицу из оставшихся строк
  3. filter(any, zip(*filter(any, arr))) — аналогично первому пункту, но уже на транспонированной матрице (отсеиваем строки, которые раньше были столбцами)
  4. zip(*filter(any, zip(*filter(any, arr)))) — транспонируем обратно

Отслеживать
ответ дан 26 мар 2020 в 12:07
user207200 user207200
5,210 8 8 золотых знаков 23 23 серебряных знака 41 41 бронзовый знак

Можно воспользоваться методом numpy.nonzero(), возвращающим индексы ненулевых элементов по каждой размерности / оси:

nz = np.nonzero(arr) res = arr[nz[0].min():nz[0].max()+1, nz[1].min():nz[1].max()+1] 
In [19]: res Out[19]: array([[0, 3, 5, 6, 7, 0, 0], [1, 1, 1, 1, 1, 7, 0], [7, 1, 1, 1, 1, 1, 7], [7, 1, 1, 1, 1, 1, 7], [7, 1, 1, 1, 1, 7, 0], [0, 7, 7, 7, 7, 0, 0]]) 

Отслеживать
ответ дан 26 мар 2020 в 14:04
MaxU — stand with Ukraine MaxU — stand with Ukraine
149k 12 12 золотых знаков 59 59 серебряных знаков 132 132 бронзовых знака
Только к верней границе +1, она же исключающая! nz[0].max() + 1 и nz[1].max() + 1 .
26 мар 2020 в 14:11
@mkkik, да совсем вылетело из головы, спасибо!
26 мар 2020 в 17:46

Воспользуйтесь функционалом numpy :

import numpy as np arr = np.array([[0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 3,5, 6, 7,0, 0, 0], [0, 1, 1,1, 1, 1,7, 0, 0], [0, 7, 1,1, 1, 1,1, 7, 0], [0, 7, 1,1, 1, 1,1, 7, 0], [0, 7, 1,1, 1, 1,7, 0, 0], [0, 0, 7,7, 7, 7,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0], [0, 0, 0,0, 0, 0,0, 0, 0]]) 
res = arr[~np.all(arr == 0, axis=1)] res = res[:, ~np.all(res == 0, axis=0)] print(res) 
[[0 3 5 6 7 0 0] [1 1 1 1 1 7 0] [7 1 1 1 1 1 7] [7 1 1 1 1 1 7] [7 1 1 1 1 7 0] [0 7 7 7 7 0 0]] 

Отслеживать
ответ дан 26 мар 2020 в 12:10
25.7k 4 4 золотых знака 21 21 серебряный знак 36 36 бронзовых знаков
~np.all(arr == 0, axis=1) можно заменить на метод any -> arr.any(axis=1)
26 мар 2020 в 12:33
@strawdog ответ хороший, потому что можно ввести любое значение non data
26 мар 2020 в 14:18

def v_trim_array(multi_array): zero_index = None for index in range(len(multi_array[0])): flag = False for array in multi_array: if array[index]: flag = True if zero_index is not None: array[zero_index] = array[index] if flag: zero_index += 1 else: if zero_index is None: zero_index = index for array in reversed(multi_array): del array[zero_index:] def h_trim_array(multi_array): zero_index = None for index, array in enumerate(multi_array): if any(array): if zero_index is not None: multi_array[zero_index] = array zero_index += 1 else: if zero_index is None: zero_index = index del multi_array[zero_index:] multi_array = [ [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 3, 5, 6, 7, 0, 0, 0], [0, 1, 1, 1, 1, 1, 7, 0, 0], [0, 7, 1, 1, 1, 1, 1, 7, 0], [0, 7, 1, 1, 1, 1, 1, 7, 0], [0, 7, 1, 1, 1, 1, 7, 0, 0], [0, 0, 7, 7, 7, 7, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0] ] # сначала убираем нулевые строки (по горизонтали) h_trim_array(multi_array) # затем убираем нулевые столбцы (по вертикали) v_trim_array(multi_array) for array in multi_array: print(' '.join(map(str, array))) # 0 3 5 6 7 0 0 # 1 1 1 1 1 7 0 # 7 1 1 1 1 1 7 # 7 1 1 1 1 1 7 # 7 1 1 1 1 7 0 # 0 7 7 7 7 0 0 

Отслеживать
ответ дан 26 мар 2020 в 11:02
6,161 3 3 золотых знака 20 20 серебряных знаков 38 38 бронзовых знаков

  • python
  • numpy
    Важное на Мете
Похожие

Подписаться на ленту

Лента вопроса

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.2.16.5008

Изменение формы массивов, добавление и удаление осей

На предыдущем занятии мы немного познакомились со способами изменения формы массивов пакета NumPy, то есть изменением их размерностей. На этом занятии поближе рассмотрим эту тему и познакомимся с наиболее употребительными функциями и свойствами, влияющих на представление массивов.

Изменение размерности массивов

Предположим, у нас имеется массив, состоящий из десяти чисел:

a = np.arange(10) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Мы уже знаем, что для изменения формы этого массива, достаточно указать свойству shape кортеж с новыми размерами, например, так:

a.shape = 2, 5 # массив размерностью 2x5

В результате изменится представление массива, на которое ссылается переменная a. Если же требуется создать новое представление массива, сохранив прежнее, то следует воспользоваться методом reshape():

b = a.reshape(10) # массив [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

И, как мы с вами говорили на предыдущем занятии, ссылки b и a будут использовать одни и те же данные, то есть, изменение массива через b:

b[0] = -1

приведет к изменению соответствующего элемента массива a:

array([[-1, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]])

Об этом всегда следует помнить. Также следует помнить, что у свойства shape и метода reshape() размерность должна охватывать все элементы массива. Например, вот такая команда:

a.shape = 3, 3

приведет к ошибке, т.к. размерность 3×3 = 9 элементов, а в массиве 10 элементов. Здесь всегда должно выполняться равенство:

n1 x n2 x … x nN = число элементов массива

Но допускается делать так:

a.shape = -1, 2 # размерность 5x2

Отрицательное значение -1 означает автоматическое вычисление размерности по первой оси. По второй берется значение 2. В этом случае получим размерность 5×2.

То же самое можно делать и в методе reshape():

b.reshape(-1, 1) # размерность 10x1 b.reshape(1, -1) # размерность 1x10

Обратите внимание, в последних двух случаях мы получаем представления двумерных массивов, преобразуя одномерный. Это важный момент, так как на выходе метода reshape() получается матрица с двумя осями (строки и столбцы), тогда как изначально массив b имел только одну ось. Не случайно последнее представление отображается с двумя квадратными скобками:

array([[-1, 1, 2, 3, 4, 5, 6, 7, 8, 9]])

Первая скобка – это первая ось (строка), а вторая скобка (вторая ось) описывает столбцы. Одномерный же массив b отображается с одной квадратной скобкой:

array([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Используя отрицательный индекс, можно делать и такие преобразования:

b.reshape(2, -1) # размерность 2x5 b.reshape(-1, 2) # размерность 5x2

Первое представление (2×5) отображается следующим образом:

array([[-1, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]])

Здесь снова мы видим две квадратные скобки (значит, массив двумерный). Первая описывает ось axis0, отвечающую за строки, а вложенные скобки описывают вторую ось axis1, отвечающую за столбцы.

Если нам требуется многомерный массив преобразовать в обычный одномерный, то можно воспользоваться методом ravel(), который возвращает новое представление, не меняя текущего:

c = b.ravel() # с ссылается на одномерное представление массива

Если же нам нужно текущий массив преобразовать в одномерный, то это можно сделать так:

b.shape = -1

Помимо свойства shape можно использовать метод resize, который выполняет подобную операцию с текущим массивом. Например:

a.resize(2, 5) # массив 2x5

Но, как мы уже говорили, вот такая строчка приведет к ошибке:

a.resize(3, 3) # ошибка: 3x3 != 10

Однако, мы все-таки можем выполнить такую операцию, указав дополнительно флаг refcheck=False:

a.resize(3, 3, refcheck=False) # массив 3x3
a.resize(4, 5, refcheck=False) # массив 4x5

В первом случае происходит удаление одного 10-го элемента, а во втором случае – добавление 4∙5 — 3∙3 = 11 нулей. Это очень удобно, когда нам нужно менять не только форму, но и размер самого массива.

Транспонирование матриц и векторов

Очень часто в математических операциях требуется выполнять транспонирование матриц и векторов, то есть, заменять строки на столбцы. Например, если имеется матрица (двумерный массив):

a = np.array([(1, 2, 3), (1, 4, 9), (1, 8, 27)])

то операция транспонирования может быть реализована так:

b = a.T

Обратите внимание, мы здесь создаем лишь новое представление тех же самых данных массива a. И изменение элементов в массиве b:

b[0, 1] = 10

приведет к соответствующему изменению значения элемента и массива a. Это следует помнить, используя операцию транспонирования.

Транспонирование векторов работает несколько иначе. Предположим, имеется одномерный массив:

x = np.arange(1, 10)

и мы выполняем операцию транспонирования:

В результате ничего не изменилось: вектор как был строкой, так строкой и остался. Почему? Дело в том, что массив x имеет только одну размерность, поэтому здесь нет понятия строк и столбцов. Соответственно, операция транспонирования ни к чему не приводит. Чтобы получить ожидаемый эффект, нужно добавить к массиву еще одну ось, например, так:

x.shape = 1, -1

И теперь, при транспонировании получим вектор-столбец:

x.T # вектор-столбец 9x1

Добавление и удаление осей

  • np.expand_dims(a, axis) – добавление новой оси;
  • np.squeeze(a[, axis]) – удаление оси (без удаления элементов).
x_test = np.arange(32).reshape(8, 2, 2) # массив 8x2x2

И нам потребовалось добавить еще одно измерение (ось), причем, в самое начало, то есть, ось axis0. Сейчас на этой оси 8 элементов – матриц 2×2, но мы хотим сделать четырехмерный массив, сохранив остальные три оси и их данные без изменений. Как раз это достаточно просто сделать с помощью функции expand_dims, следующим образом:

x_test4 = np.expand_dims(x_test, axis=0)

Обращаясь к свойству shape:

x_test4.shape # (1, 8, 2, 2)

Видим, что массив стал четырехмерным и первая добавленная ось axis0 содержит один элемент – трехмерный массив 8x2x2. При необходимости, мы всегда можем добавить новый элемент на эту ось:

a = np.append(x_test4, x_test4, axis=0) # размерность (2, 8, 2, 2)

или удалить ненужные элементы:

b = np.delete(a, 0, axis=0) # размерность (1, 8, 2, 2)

Здесь второй параметр 0 – индекс удаляемого элемента на оси axis0. Если нам нужно добавить последнюю ось в массиве, то для этого можно записать такую команду:

b = np.expand_dims(x_test4, axis=-1) # размерность (1, 8, 2, 2, 1)

Отрицательный индекс -1 – это следующая с конца ось. Если указать индекс -2, то добавится предпоследняя ось и так далее. Отрицательные индексы очень удобно использовать при работе с массивами произвольных размерностей. Следующая функция squeeze позволяет удалить все оси с одним элементом. Например, строчка:

c = np.squeeze(b) # размерность (8, 2, 2)

превращает массив размерностью (1, 8, 2, 2) в массив размерностью (8, 2, 2). При необходимости, дополнительно мы можем самостоятельно указать оси, которые следует удалять, например, так:

c = np.squeeze(b, axis=0) # удалит только ось axis0, не затронув другие

Но, если указать ось с числом элементов больше 1, то возникнет ошибка:

c = np.squeeze(b, axis=1) # ошибка, на оси axis1 8 элементов

Объект newaxis

В NumPy добавлять новые оси иногда удобнее с помощью специального объекта np.newaxis. Например, пусть у нас есть одномерный массив:

a = np.arange(1, 10) # array([1, 2, 3, 4, 5, 6, 7, 8, 9])

У него одна ось – одно измерение. Добавим еще одну ось, допустим, в начало. С помощью объекта np.newaxis это можно сделать так:

b = a[np.newaxis, :] # добавление оси axis0 b.shape # (1, 9)

Или, можно прописать сразу две оси:

c = a[np.newaxis, :, np.newaxis] c.shape # (1, 9, 1)

Как видите, это достаточно удобная операция.

Видео по теме

© 2024 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта

Свойства и представления массивов, создание их копий

Это занятие начнем с изучения основных свойств массивов NumPy. С некоторыми из них мы уже знакомы. Например, если создать вот такой одномерный массив:

a = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])

то через точку нам будут доступны методы и свойства класса array. В частности, следующая строчка:

a.dtype

возвратит текущий тип данных элементов массива:

Но через него мы также можем поменять тип данных, если присвоить ему другое определение:

a.dtype = np.int8()

Мы здесь используем класс int8 для описания целочисленного типа в 8 бит (1 байт). Все данные будут преобразованы и при выводе массива увидим значения:

array([-102, -103, -103, -103, -103, -103, -71, 63, -102, -103, -103,
-103, -103, -103, -55, 63, 51, 51, 51, 51, 51, 51,
-45, 63, -102, -103, -103, -103, -103, -103, -39, 63, 0,
0, 0, 0, 0, 0, -32, 63, 51, 51, 51, 51,
51, 51, -29, 63, 102, 102, 102, 102, 102, 102, -26,
63, -102, -103, -103, -103, -103, -103, -23, 63, -51, -52,
-52, -52, -52, -52, -20, 63], dtype=int8)

Их стало больше. Изначально имели длину массива в 9 элементов, теперь стало:

a.size # 72 элемента

Свойство size возвращает число элементов массива вне зависимости от его размерности. Почему массив стал иметь 72 элемента вместо 9? Ну, во-первых, можно заметить, что на каждый исходный элемента приходится 72:9 = 8 чисел типа int8 (1 байт). То есть, изначальный тип float64 был разложен на 8 байт. Что вполне логично, так как 64 бит = 8 байт. И, фактически, все исходные вещественные данные были просто представлены набором байт. Отсюда такое превращение одного массива в другой. При этом потерь данных не произошло и, если мы снова вернем тип float64:

a.dtype = np.float64()

то увидим исходный массив:

array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])

По этой же причине, если менять тип в уже существующем массиве, скажем, на float32:

a.dtype = 'float32'

то число его элементов увеличится вдвое:

a.size # 18 элементов

а содержимое станет следующим:

array([-1.58818684e-23, 1.44999993e+00, -1.58818684e-23, 1.57499993e+00,
4.17232506e-08, 1.64999998e+00, -1.58818684e-23, 1.69999993e+00,
0.00000000e+00, 1.75000000e+00, 4.17232506e-08, 1.77499998e+00,
2.72008302e+23, 1.79999995e+00, -1.58818684e-23, 1.82499993e+00,
-1.07374184e+08, 1.84999990e+00], dtype=float32)

Вот так ведут себя массивы NumPy при изменении их типов данных.

Далее, если требуется узнать сколько байт занимает один элемент, то можно воспользоваться свойством:

a.itemsize # вернет 4 (байта)

Соответственно, размер памяти для всего массива можно вычислить так:

a.size*a.itemsize # вернет 72 (байта)

Представления массивов

Давайте теперь создадим массив размерностью 3x4x5:

b = np.ones( (3, 4, 5) )

Узнать количество его осей, можно через свойство ndim (доступно только для чтения):

b.ndim # вернет значение 3

Чтобы определить размеры каждой из осей, используется свойство shape:

b.shape # вернет кортеж (3, 4, 5)

С его помощью мы можем менять размерность массива, главное, чтобы общее число элементов оставалось прежним. Например, сделать так:

b.shape = 60 # все 60 элементов вытянутся в строку b.shape = (12, 5) # массив размерностью 12x5

И так далее. Используя свойство shape мы можем менять представление одних и тех же данных текущего массива. Обратите внимание, здесь не создаются новые массивы, а лишь меняется представление текущего. Это очень важный момент при работе с NumPy:

Один и тот же массив в NumPy может иметь разное представление и математически и программно обрабатываться по разному.

Такое весьма полезное и гибкое поведение влечет некоторые следствия. Например, мы хотим сформировать новый массив на основе массива b, просто изменив его форму (представление):

c = b.reshape(3, 2, 10)

Мы здесь воспользовались методом reshape, который возвращает массив с новой указанной размерностью (прежний массив остается без изменений). В результате, переменная c будет ссылаться на массив размерами 3x2x10, а переменная b – на массив 12×5. Но данные при этом, будут использоваться одни и те же:

Мы легко можем в этом убедиться. Изменим элемент в массиве b:

b[0, 0] = 10

и это скажется на первом значении массива c. Хотя id этих ссылок будут разными:

print( id(b), id(c) ) # разные значения

Это связано с тем, что они ссылаются на разные представления одного и того же массива, а не на его данные. То есть, пример функции reshape() показывает, что в пакете NumPy разделяются понятия данные и представление этих данных. В результате, одни и те же данные могут иметь множество разных представлений. Это очень удобно с точки зрения экономии памяти, когда один и тот же массив можно использовать и как одномерный вектор и как матрицу.

Также при работе с NumPy следует помнить, что представления могут формироваться разными способами. Метод reshape() – это лишь один частный пример. Если выполнить транспонирование матрицы b и использовать для этого свойство T:

d = b.T # T – транспонирование матрицы (12, 5)

то получим еще одно представление, на которое будет ссылаться переменная d, размерностью:

d.shape # возвратит кортеж (5, 12)

При этом, сама матрица b останется неизменной.

Как же узнать, когда создается новый, независимый массив, а когда его представление? В идеале, нужно просто знать, какие функции, методы и свойства возвращают новое представление, а какие создают новый массив. Но на начальном этапе об этом легко догадаться из логики работы самой программы: любое изменение формы, как правило, связано с созданием нового представления или изменением текущего. Поэтому, здесь больших проблем, обычно, не возникает. Главное понимать, что в NumPy массивы и их представления – это разные понятия.

Метод view() для создания представления

У каждого массива array существует метод view(), который возвращает копию его представления. О чем здесь речь? Смотрите. Предположим, мы присваиваем один массив другому:

a = np.array([1,2,3,4,5,6,7,8,9]) b = a

Зная, что в языке Python переменные – это ссылки на объекты, то a и b будут просто ссылаться на один и тот же массив, копирования здесь никакого происходить не будет. Следовательно, если дальше по программе изменить форму массива через одну из этих ссылок, например, так:

a.shape = 3,3

то вторая ссылка b также будет ссылаться на это измененное представление. В больших и сложных проектах такое поведение может приводить к неожиданным ошибкам, когда программист ожидает вектор, а получает матрицу. Чтобы разрешить эту проблему достаточно создать новое представление начального массива a с помощью метода view():

a = np.array([1,2,3,4,5,6,7,8,9]) b = a.view() # создание нового представления

Тогда, меняя форму через ссылку a:

a.shape = 3,3

это уже никак не скажется на форме того же самого массива, доступного через ссылку b:

array([1, 2, 3, 4, 5, 6, 7, 8, 9])

Создание копий массивов

Иногда в программе все же нужно создавать копии массивов. Это можно сделать несколькими способами. В последних версиях NumPy функция array() возвращает копию переданного ей массива, например:

a = np.array([1,2,3,4,5,6,7,8,9]) b = np.array( a ) # создается копия массива

Или же, копию можно получить с помощью метода copy объекта array:

c = a.copy() # создание копии массива

При этом происходит копирование всех свойств объекта array. Последний вариант предпочтителен, когда нам нужно получить полную копию массива, а не просто новый объект array.

Видео по теме

#1. Пакет numpy — установка и первое знакомство | NumPy уроки

#2. Основные типы данных. Создание массивов функцией array() | NumPy уроки

#3. Функции автозаполнения, создания матриц и числовых диапазонов | NumPy уроки

#4. Свойства и представления массивов, создание их копий | NumPy уроки

#5. Изменение формы массивов, добавление и удаление осей | NumPy уроки

#6. Объединение и разделение массивов | NumPy уроки

#7. Индексация, срезы, итерирование массивов | NumPy уроки

#8. Базовые математические операции над массивами | NumPy уроки

#9. Булевы операции и функции, значения inf и nan | NumPy уроки

#10. Базовые математические функции | NumPy уроки

#11. Произведение матриц и векторов, элементы линейной алгебры | NumPy уроки

#12. Множества (unique) и операции над ними | NumPy уроки

#13. Транслирование массивов | NumPy уроки

© 2024 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта

Изменить размерность матрицы без использования NumPy

Author24 — интернет-сервис помощи студентам

Без использования NumPy изменить размерность матрицы
Без использования NumPy изменить размерность матрицы. Например из матрицы 2*3 должна получится.

Операции с массивами без использования NumPy
Вопрос такой, с NumPy я смогу это сделать, но а если нету этого модуля на пк, то как решить.

Изменить размерность массива без потери данных
Что нужно использовать для того чтобы изменить размерность массива, без потери данных. т.е. .

Изменить размерность матрицы
Помогите пожалуйста, подскажите как сделать так, чтобы размерность матрицы была не вложенной, а.

Матрицы (без модуля NumPy)
В каждом столбце матрицы вещественных чисел P(k*m) заменить минимальный элемент суммой.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *