2012-03-19 18 views
6

Zastanawiam się, jaki jest najlepszy sposób normalizacji/standaryzacji numpy recarray. Aby było jasne, nie mówię o macierzy matematycznej, ale o tablicy rekordów, która również ma np. kolumny tekstowe (takie jak etykiety).Normalizuj/Standaryzuj numpy recarray

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

Jak widać, nie mogę np. proces a[:,:-1], ponieważ kształt jest jednowymiarowy.

Najlepszym znalazłem jest iteracyjne nad wszystkie kolumny:

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

Wszelkie bardziej elegancki sposób to zrobić? Czy istnieje gdzieś metoda "normalizacji" lub "standaryzacji"?

Odpowiedz

6

Istnieje wiele sposobów, aby to zrobić, ale niektóre są czystsze niż inne.

Zwykle w numpy przechowujesz dane ciągu w oddzielnej tablicy.

(Rzeczy są nieco bardziej na niskim poziomie niż, powiedzmy, ramki danych R w. Zazwyczaj po prostu zawinąć rzeczy w klasie dla związku, ale zachować różne typy danych rozdzielić.)

Szczerze numpy ISN Zoptymalizowany pod kątem obsługi "elastycznych" typów danych, takich jak ten (choć z pewnością może to zrobić). Rzeczy takie jak pandas zapewniają lepszy interfejs dla "podobnych do arkusza kalkulacyjnego" danych (a pandy to tylko warstwa na wierzchu numpy).

Jednak ustrukturyzowane tablice (co tutaj masz) pozwolą ci je pokroić w kolumny, gdy przejdziesz na listę nazw pól. (Np data[['col1', 'col2', 'col3']])

W każdym razie, jednym ze sposobów jest zrobić coś takiego:

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) 

Jest to jednak dalekie od ideału. Jeśli chcesz wykonać operację na miejscu (tak jak obecnie), najprostszym rozwiązaniem jest to, co już masz: Wystarczy powtórzyć nazwy pól.

Nawiasem mówiąc, stosując pandas, chcesz zrobić coś takiego:

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

+1 Dziękuję. Jest to bardzo pouczająca i wnikliwa odpowiedź. Podział zbioru danych na kolumny liczbowe i nieliczbowe jest prawdopodobnie drogą do zrobienia. To sprawia, że ​​wiele innych operacji jest dobrze zdefiniowanych i faktycznie to właśnie próbowałem zrobić. Nie wiedziałem o możliwości użycia 'data [list]' do wybrania wielu kolumn. –

1

Jaka wersja NumPy używasz? W wersji 1.5.1 nie widzę takiego zachowania. Zrobiłem krótki plik tekstowy, na przykład, zapisane jako test.txt:

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

Kiedy następnie wykonać następujący kod, to co mam:

>>> 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 

Zastanawiam się tylko, co różni się Twoje dane.

+0

Uwaga: to miało być komentarzem, a nie odpowiedzią ... wystarczyło więcej miejsca, aby wstawić przykład powyżej. – ely

+0

Co innego jest to, że dostajesz tablicę ciągów, a nie tablicę strukturalną. Spójrz na typ "a" w twoim przykładzie. –

+0

Oczywiście, ale co powoduje, że przychodząca tablica ma "strukturę"? Jeśli jest to tylko plik csv, czy 'genfromtxt()' nie zawsze tworzy tablicę ciągów znaków? – ely