NumPy'de bir dizi nasıl normalleştirilir?


209

Bir NumPy dizisinin normuna sahip olmak istiyorum. Daha spesifik olarak, bu işlevin eşdeğer bir sürümünü arıyorum

def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0: 
       return v
    return v / norm

Böyle orada şey mi skearnyoksa numpy?

Bu işlev v, 0 vektörünün bulunduğu bir durumda çalışır .


3
Yazdıklarının nesi yanlış?
ali_m

5
Bu gerçekten bir endişe ise, epsilon'un küçük bir tolerans olduğu <epsilon normunu kontrol etmelisiniz. Buna ek olarak, sessizce bir norm sıfır vektörü geri vermezdim, raisebir istisna olurdu !
Hooked

4
benim fonksiyonum çalışıyor ama python daha yaygın kütüphane içinde bir şey olup olmadığını bilmek istiyorum. Farklı makine öğrenme işlevleri yazıyorum ve kodu daha net ve okunabilir hale getirmek için çok fazla yeni işlev tanımlamaktan kaçınmak istiyorum
Donbeo

1
Birkaç hızlı test yaptım ve bunun CPU'da numpy 1.15.1'den x/np.linalg.norm(x)çok daha yavaş olmadığını (yaklaşık% 15-20) buldum x/np.sqrt((x**2).sum()).
Bill

Yanıtlar:


164

Scikit-learn kullanıyorsanız şunları kullanabilirsiniz sklearn.preprocessing.normalize:

import numpy as np
from sklearn.preprocessing import normalize

x = np.random.rand(1000)*10
norm1 = x / np.linalg.norm(x)
norm2 = normalize(x[:,np.newaxis], axis=0).ravel()
print np.all(norm1 == norm2)
# True

2
Cevabınız için teşekkür ederiz, ancak sklearn.preprocessing.normalize öğesinin = (n,) veya (n, 1) vektörü ile de çalıştığından emin misiniz? Bu kütüphane ile bazı sorunlar yaşıyorum
Donbeo

normalizebir 2D giriş gerektirir. axis=Normalleştirmeyi girdi dizinizin satırlarına veya sütunlarına uygulamak isteyip istemediğinizi belirtmek için bağımsız değişkeni iletebilirsiniz .
ali_m

9
Normalleştirme işlevinin 'norm' bağımsız değişkeninin 'l1' veya 'l2' olabileceğini ve varsayılan değerin 'l2' olduğunu unutmayın. Vektörünüzün toplamının 1 olmasını istiyorsanız (örn. Olasılık dağılımı) normalleştirme fonksiyonunda norm = 'l1' kullanmalısınız.
Ash

2
Ayrıca np.linalg.norm(x)varsayılan olarak 'l2' normu hesaplar. Vektörünüzün toplamının 1 olmasını istiyorsanıznp.linalg.norm(x, ord=1)
Omid

Not: x ndarray, normalize()işlevle çalışabilmesi için olmalıdır . Aksi takdirde bir olabilir list.
Ramin Melikov

48

Böyle bir işlev dahil pillerin bir parçası olsaydı güzel olduğunu kabul ediyorum. Ama bildiğim kadarıyla değil. İşte keyfi eksenler ve en iyi performansı veren bir versiyon.

import numpy as np

def normalized(a, axis=-1, order=2):
    l2 = np.atleast_1d(np.linalg.norm(a, order, axis))
    l2[l2==0] = 1
    return a / np.expand_dims(l2, axis)

A = np.random.randn(3,3,3)
print(normalized(A,0))
print(normalized(A,1))
print(normalized(A,2))

print(normalized(np.arange(3)[:,None]))
print(normalized(np.arange(3)))

Ben derin ali_m çözümünü test etmedi ama bazı basit durumlarda çalışıyor gibi görünüyor. İşlevinizin daha iyi olduğu durumlar var mı?
Donbeo

1
Bilmiyorum; ancak keyfi eksenler üzerinde çalışır ve uzunluk 0 vektörleri için ne olacağı üzerinde açık bir kontrole sahibiz.
Eelco Hoogendoorn

1
Çok hoş! Bence düzen muhtemelen eksenden önce gelmelidir - bu numpy olmalıdır.
Neil G

@EelcoHoogendoorn Sipariş = 2'nin neden diğerleri üzerinde seçildiğini merak mı ediyorsunuz?
Henry Thornton

7
Çünkü Öklid / pisagor normu en sık kullanılanıdır; kabul etmez misin
Eelco Hoogendoorn

21

L1 normunu almak için ord belirtebilirsiniz. Sıfır bölünmesini önlemek için eps kullanıyorum, ama bu belki de harika değil.

def normalize(v):
    norm=np.linalg.norm(v, ord=1)
    if norm==0:
        norm=np.finfo(v.dtype).eps
    return v/norm

7
[inf, 1, 2]verimi normalleştirmek [nan, 0, 0], ama olmamalı [1, 0, 0]mı?
pasbi

13

Bu sizin için de işe yarayabilir

import numpy as np
normalized_v = v / np.sqrt(np.sum(v**2))

ancak vuzunluğu 0 olduğunda başarısız olur .


10

Çok boyutlu verileriniz varsa ve her eksenin maksimum değerine veya toplamına normalleştirilmesini istiyorsanız:

def normalize(_d, to_sum=True, copy=True):
    # d is a (n x dimension) np array
    d = _d if not copy else np.copy(_d)
    d -= np.min(d, axis=0)
    d /= (np.sum(d, axis=0) if to_sum else np.ptp(d, axis=0))
    return d

Numpys tepeden tepeye işlevini kullanır .

a = np.random.random((5, 3))

b = normalize(a, copy=False)
b.sum(axis=0) # array([1., 1., 1.]), the rows sum to 1

c = normalize(a, to_sum=False, copy=False)
c.max(axis=0) # array([1., 1., 1.]), the max of each row is 1

Orijinal matristeki tüm değerlerin aynı olup olmadığına dikkat edin, sonra ptp 0 olur. 0'a bölünme nan döndürür.
Milso

8

Christoph Gohlke'nin unit_vector()popüler dönüşüm modülünde vektörleri normalleştirme işlevi de var :

import transformations as trafo
import numpy as np

data = np.array([[1.0, 1.0, 0.0],
                 [1.0, 1.0, 1.0],
                 [1.0, 2.0, 3.0]])

print(trafo.unit_vector(data, axis=1))

7

Sci-kit öğrenmesinden bahsettiniz, bu yüzden başka bir çözüm paylaşmak istiyorum.

sci-kit öğrenmek MinMaxScaler

Sci-kit öğrenmede, MinMaxScalerdeğer aralığını istediğiniz gibi özelleştirebilen bir API var .

Ayrıca bizim için NaN sorunlarıyla da ilgileniyor.

NaN'ler eksik değerler olarak kabul edilir: uyumda göz ardı edilir ve dönüşümde tutulur. ... referans 1'e bakınız.

Kod örneği

Kod basit, sadece yazın

# Let's say X_train is your input dataframe
from sklearn.preprocessing import MinMaxScaler
# call MinMaxScaler object
min_max_scaler = MinMaxScaler()
# feed in a numpy array
X_train_norm = min_max_scaler.fit_transform(X_train.values)
# wrap it up if you need a dataframe
df = pd.DataFrame(X_train_norm)
Referans

6

Olmadan sklearnve sadece kullanarak numpy. Sadece bir fonksiyon tanımlayın:

Satırların samples ( axis= 1) değişkenleri ve sütunları olduğunu varsayarsak :

import numpy as np

# Example array
X = np.array([[1,2,3],[4,5,6]])

def stdmtx(X):
    means = X.mean(axis =1)
    stds = X.std(axis= 1, ddof=1)
    X= X - means[:, np.newaxis]
    X= X / stds[:, np.newaxis]
    return np.nan_to_num(X)

çıktı:

X
array([[1, 2, 3],
       [4, 5, 6]])

stdmtx(X)
array([[-1.,  0.,  1.],
       [-1.,  0.,  1.]])

4

3B tensörde saklanan n boyutlu özellik vektörlerini normalleştirmek istiyorsanız PyTorch'u da kullanabilirsiniz:

import numpy as np
from torch import FloatTensor
from torch.nn.functional import normalize

vecs = np.random.rand(3, 16, 16, 16)
norm_vecs = normalize(FloatTensor(vecs), dim=0, eps=1e-16).numpy()

4

3D vektörler ile çalışıyorsanız, size kısaca toolbelt kullanarak yapabilirsiniz VG . Numpy'nin üstünde hafif bir katmandır ve tek değerleri ve yığılmış vektörleri destekler.

import numpy as np
import vg

x = np.random.rand(1000)*10
norm1 = x / np.linalg.norm(x)
norm2 = vg.normalize(x)
print np.all(norm1 == norm2)
# True

Kütüphaneyi, son kullanımımda, bunun gibi kullanımlar tarafından motive edildiğini yarattım: NumPy'de çok ayrıntılı olan basit fikirler.


3

En yüksek hassasiyete ihtiyacınız yoksa, işleviniz aşağıdakilere indirgenebilir:

v_norm = v / (np.linalg.norm(v) + 1e-16)

3

Çok boyutlu dizi ile çalışıyorsanız hızlı çözüm mümkündür.

Diyelim ki son sıra ile normalleştirmek istediğimiz 2D dizimiz var, bazı sıralar sıfır normlu.

import numpy as np
arr = np.array([
    [1, 2, 3], 
    [0, 0, 0],
    [5, 6, 7]
], dtype=np.float)

lengths = np.linalg.norm(arr, axis=-1)
print(lengths)  # [ 3.74165739  0.         10.48808848]
arr[lengths > 0] = arr[lengths > 0] / lengths[lengths > 0][:, np.newaxis]
print(arr)
# [[0.26726124 0.53452248 0.80178373]
# [0.         0.         0.        ]
# [0.47673129 0.57207755 0.66742381]]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.