Нормализовать / стандартизировать повторный массив - PullRequest
7 голосов
/ 19 марта 2012

Интересно, каков наилучший способ нормализации / стандартизации numpy recarray.Чтобы было понятно, я говорю не о математической матрице, а о массиве записей, который также имеет, например, текстовые столбцы (например, метки).

a = np.genfromtxt("iris.csv", delimiter=",", dtype=None)
print a.shape
> (150,)

Как видите, я не могу, например, обработать a[:,:-1], поскольку форма одномерна.

Лучшее, что я нашел, - это перебрать все столбцы:

for nam in a.dtype.names[:-1]:
    col = a[nam]
    a[nam] = (col - col.min()) / (col.max() - col.min())

Есть ли более элегантный способ сделать это?Есть ли какой-нибудь метод, например, "нормализовать" или "стандартизировать" где-нибудь?

Ответы [ 2 ]

7 голосов
/ 19 марта 2012

Есть несколько способов сделать это, но некоторые чище, чем другие.

Обычно в numpy строковые данные хранятся в отдельном массиве.

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

Честно говоря, numpy не оптимизирован для обработки таких "гибких" типов данных (хотя, безусловно, он может это делать). Такие вещи, как pandas обеспечивают лучший интерфейс для данных, подобных «электронным таблицам» (а pandas - это просто слой поверх numpy).

Однако, структурированные массивы (что у вас есть здесь) позволят вам разрезать их по столбцам, когда вы передадите список имен полей. (например, data[['col1', 'col2', 'col3']])

В любом случае, один из способов сделать что-то вроде этого:

import numpy as np

data = np.recfromcsv('iris.csv')

# In this case, it's just all but the last, but we could be more general
# This must be a list and not a tuple, though.
float_fields = list(data.dtype.names[:-1])

float_dat = data[float_fields]

# Now we just need to view it as a "regular" 2D array...
float_dat = float_dat.view(np.float).reshape((data.size, -1))

# And we can normalize columns as usual.
normalized = (float_dat - float_dat.min(axis=0)) / float_dat.ptp(axis=0)

Однако это далеко от идеала. Если вы хотите выполнить операцию на месте (как и сейчас), то самое простое решение - это то, что у вас уже есть: просто переберите имена полей.

Кстати, используя pandas, вы бы сделали что-то вроде этого:

import pandas
data = pandas.read_csv('iris.csv', header=None)

float_dat = data[data.columns[:-1]]
dmin, dmax = float_dat.min(axis=0), float_dat.max(axis=0)

data[data.columns[:-1]] = (float_dat - dmin) / (dmax - dmin)
1 голос
/ 19 марта 2012

Какую версию NumPy вы используете? С версией 1.5.1 я не получаю такого поведения. Я сделал короткий текстовый файл в качестве примера, сохраненный как test.txt:

last,first,country,state,zip
tyson,mike,USA,Nevada,89146
brady,tom,USA,Massachusetts,02035

Когда я затем выполняю следующий код, я получаю следующее:

>>> import numpy as np
>>> a = np.genfromtxt("/home/ely/Desktop/Python/test.txt",delimiter=',',dtype=None)
>>> print a.shape
(3,5)
>>> print a
[['last' 'first' 'country' 'state' 'zip']
 ['tyson' 'mike' 'USA' 'Nevada' '89146']
 ['brady' 'tom' 'USA' 'Massachusetts' '02035']]
>>> print a[0,:-1]
['last' 'first' 'country' 'state']
>>> print a.dtype.names
None

Мне просто интересно, что отличается в ваших данных.

...