Как произвольно выбирать массивы NumPy в Python без scikit-learn или Pandas.

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

В этой статье мы узнаем, как случайным образом выбирать и управлять данными в массивах NumPy для машинного обучения без scikit-learn или Pandas.

Разбивать и складывать массивы

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

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

Чтобы начать работу над проектом машинного обучения, который предсказывает кошек и собак. В массиве может быть несколько столбцов и строк или тысячи (или миллионы!) - в любом случае основные шаги будут одинаковыми: разделение и стек.

Разделить набор данных

Вам может потребоваться разделить набор данных по двум разным причинам. Сначала разделите весь набор данных на набор для обучения и набор для тестирования. Во-вторых, отделите столбцы функций от целевого столбца. Например, разделите 80% данных на обучающие и 20% на тестовые, а затем разделите функции из столбцов в каждом подмножестве.

# given a one dimensional array
one_d_array = np.array([1,2,3,4,5,6,7,8,9,10])
# randomly select without replacement
train = np.random.choice(one_d_array, size=8, replace=False)
print(train)
""" output
[ 3  5 10  9  6  8  4  7]
"""

Более того, вместо того, чтобы всегда выбирать первые 80% выборок по мере их появления в массиве, это помогает случайным образом выбирать подмножества. В результате, когда мы разделяем, мы на самом деле хотим выбрать случайным образом, а затем разделить.

При случайном выборе первое, что вы можете сделать, это np.random.choice (). Например, чтобы случайным образом выбрать 80% массива, мы можем выбрать 8 из 10 элементов случайным образом и без замены. Как показано выше, мы можем случайным образом выбирать из одномерного массива чисел.

Случайная выборка особенно желательна, если первая половина данных содержит всех кошек, поскольку это не позволяет нам проводить обучение только на кошках и без собак.

# a example array of data extended from Figure 1
# with shape (10, 4)
animals = np.array([[1,0,1,0],
                    [1,1,0,1],
                    [1,0,1,0],
                    [1,1,0,1],
                    [1,1,0,1],
                    [1,0,1,0],
                    [1,1,0,1],
                    [1,0,1,0],
                    [1,0,1,0],
                    [1,1,0,1]])
train = np.random.choice(animals, size=8, replace=True)
print(train)
""" output
ValueError Traceback (most recent call last)
<ipython-input-44-ecab0b58674d> in <module>()
----> 1 train = np.random.choice(animals, size=8, replace=True)
      2 print(train)
mtrand.pyx in numpy.random.mtrand.RandomState.choice()
ValueError: a must be 1-dimensional
"""

К сожалению, np.random.choice () работает только с одномерными массивами. В результате он не может выполнить выборку из нашего массива животных и возвращает ужасное сообщение об ошибке. Как обойти эту проблему?

Первый вариант. Поверните проблему в сторону и вместо непосредственной выборки массива выберите индекс массива, а затем разделите массив по индексу.

Если в массиве 10 строк, идея состоит в том, чтобы случайным образом выбрать числа от 0 до 9, а затем проиндексировать массив по полученным спискам чисел.

# length of data as indices of n_data
n_data = animals.shape[0]
# get n_samples based on percentage of n_data
n_samples = int(n_data * .8)
# make n_data a list from 0 to n
n_data  = list(range(n_data))
# randomly select from range of n_data as indices
idx_train = np.random.choice(n_data, n_samples, replace=False)
idx_test = list(set(n_data) - set(idx_train))
print('indicies')
print(idx_train, idx_test)
print('test array')
print(animals[idx_test, ])
""" output of split indices and the smaller test array
indicies
[5 4 6 3 2 1 7 0] [8, 9]
test array
[[1 0 1 0]
 [1 1 0 1]]
"""

Второй вариант. Если цель состоит в том, чтобы вернуть случайные подмножества массива, другой способ достижения цели - сначала перетасовать массив, а затем выполнить его выборку. Обратите внимание, что в отличие от некоторых других методов, np.random.shuffle () выполняет операцию на месте. Учитывая перемешанный массив, нарежьте его, но вы хотите вернуть подмножества.

В этом втором методе, поскольку массив перемешивается, простое взятие первых 80% строк представляет собой случайную выборку.

# shuffle the same array as before, in place
np.random.shuffle(animals)
# slice the first-n and rest-of-n of an array
tst = animals[:8, ]
trn = animals[8:, ]

Разделить массив

Раньше мы разделяли весь набор данных, но как насчет массива по столбцам? В примере массива животных столбцы 0, 1 и 2 являются характеристиками, а столбец 3 - целью. Конечно, мы могли бы просто вернуть 3-й столбец, но что, если у нас будет 5 или 100 функций? В этом случае отрицательная индексация - прекрасный друг.

# negative index to slice the last column
# works, no matter how many columns 
trgts = animals[:,-1]
print(trgts)
""" output is a flattened version of the last column
[0 1 1 1 0 0 1 0 1 0]
"""

В приведенном выше примере отрицательный индекс отсекает последний столбец, но теперь это одномерный массив. В некоторых случаях это желательно; однако массивы функций и целей имеют разные формы - это проблема, если мы хотим снова собрать их вместе. Вместо этого мы можем позаботиться о том, чтобы нарезать количество строк с отрицательной индексацией, чтобы зарезервировать 2D-форму.

# len data as indices of n_data
n_data = animals.shape[0]
# n_samples based on percentage of n_data
n_samples = int(n_data * .8)
# m_samples as the difference (the rest)
m_samples = n_data - n_samples
# slice n_samples up until the last column as feats
train_feats = animals[:n_samples, :-1]
# slice n_samples of only the last column as trgts
train_trgts = animals[:n_samples, -1:]
# ... repeat for m_samples

Массив стека

На этом этапе мы перемешали и разделили набор данных и отделили объекты от целевых объектов. А теперь, как насчет того, чтобы снова собрать все воедино? Чтобы складывать влево-вправо и вверх-вниз, мы можем использовать np.hstack () и np.vstack ().

Чтобы снова собрать Шалтай-Болтай, сложите их по горизонтали, а затем по вертикали.

# combine side-by-side
train = np.hstack((train_feats, train_trgts))
test = np.hstack((test_feats, test_trgts))
# combined up-down, returns original array
orig = np.vstack((train, test))

Структурные массивы

Если вы не можете или не можете использовать Pandas и имеете только NumPy, есть несколько способов использовать возможности NumPy с легкостью Pandas без фактического импорта Pandas. Но как?

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

В структурированном массиве индекс столбца 0 также индексируется словом «мех» и т. Д.

# import a new library in addition to numpy
import numpy.lib.recfunctions as rfn
# column names as a list of strings
col_names = ['fur', 'meow', 'bark', 'label']
# an array
animals = np.array([[1,0,1,0],
                    [2,1,0,1],
                    [3,0,1,0],
                    [4,1,0,1]])
# necessary to set the datatype for each cell
# set n dtypes to integer based on col_names
dtypes = np.dtype([(n, 'int') for n in col_names])
# use refunctions library to set array to structured
structured = rfn.unstructured_to_structured(animals, dtypes)
print(structured['fur'])
""" output
[1 2 3 4]
"""

Подробнее об операциях со структурированными массивами см.« Объединение структурированных массивов ; эти методы обнаруживаются через Stack Overflow на странице https://stackoverflow.com/questions/55577256/numpy-how-to-add-column-names-to-numpy-array.

Резюме

В этой истории я представляю некоторые функции NumPy, которые я изучил и на которые полагался, когда проходил университетский курс машинного обучения. Курс ограничивал использование предварительно созданных библиотек, таких как sci-kit learn и Pandas, для усиления конкретных целей обучения. Это лишь некоторые из моих заметок, которые, я надеюсь, будут полезны другим, ищущим несколько советов и рекомендаций по NumPy с машинным обучением.

Спасибо, что прочитали, надеюсь, это сработает для вас. Дайте мне знать, если я смогу внести какие-либо улучшения или затронуть новые темы.