2012-01-18 57 views
59

Cho một 3 lần 3 NumPy mảngLàm thế nào để chuẩn hóa một mảng numpy 2 chiều trong python ít tiết?

a = numpy.arange(0,27,3).reshape(3,3) 

# array([[ 0, 3, 6], 
#  [ 9, 12, 15], 
#  [18, 21, 24]]) 

Để bình thường hóa các hàng của mảng 2 chiều tôi nghĩ

row_sums = a.sum(axis=1) # array([ 9, 36, 63]) 
new_matrix = numpy.zeros((3,3)) 
for i, (row, row_sum) in enumerate(zip(a, row_sums)): 
    new_matrix[i,:] = row/row_sum 

Có phải là một cách tốt hơn, chứ không phải là có?

Có lẽ để làm rõ: Bằng cách chuẩn hóa ý tôi, tổng của các mục nhập mỗi hàng phải là một. Nhưng tôi nghĩ điều đó sẽ rõ ràng đối với hầu hết mọi người.

+6

cẩn thận, "bình thường hóa" thường có nghĩa là * vuông * tổng của các thành phần là một. Định nghĩa của bạn hầu như không rõ ràng đối với hầu hết mọi người;) – coldfix

Trả lời

82

Broadcasting là thực sự tốt cho việc này:

row_sums = a.sum(axis=1) 
new_matrix = a/row_sums[:, numpy.newaxis] 

row_sums[:, numpy.newaxis] reshapes row_sums từ việc (3,) để trở thành (3, 1). Khi bạn làm a/b, ab được phát sóng với nhau.

Bạn có thể tìm hiểu thêm về phát sónghere hoặc thậm chí tốt hơn here.

+0

cảm ơn bạn rất nhiều! – Aufwind

+8

Điều này có thể được đơn giản hóa hơn nữa bằng cách sử dụng 'a.sum (axis = 1, keepdims = True)' để giữ kích thước cột đơn, mà sau đó bạn có thể phát sóng mà không cần phải sử dụng 'np.newaxis'. –

+3

nếu bất kỳ row_sums nào bằng 0 thì sao? – asdf

7

Tôi nghĩ rằng điều này sẽ làm việc,

a = numpy.arange(0,27.,3).reshape(3,3) 

a /= a.sum(axis=1)[:,numpy.newaxis] 
+2

tốt. lưu ý sự thay đổi của dtype thành arange, bằng cách gắn thêm dấu thập phân vào 27. – wim

51

Scikit-học có chức năng bình thường hóa cho phép bạn áp dụng normalizations khác nhau. Các "làm cho nó tổng hợp để 1" là chuẩn mực L1, và lấy đó làm:

from sklearn.preprocessing import normalize 
matrix = numpy.arange(0,27,3).reshape(3,3).astype(numpy.float64) 

#array([[ 0., 3., 6.], 
# [ 9., 12., 15.], 
# [ 18., 21., 24.]]) 

normed_matrix = normalize(matrix, axis=1, norm='l1') 

#[[ 0.   0.33333333 0.66666667] 
#[ 0.25  0.33333333 0.41666667] 
#[ 0.28571429 0.33333333 0.38095238]] 

Bây giờ hàng của bạn sẽ tổng hợp để 1.

+5

Cuối cùng là câu trả lời cho thấy đầu ra ... –

0

Trong trường hợp bạn đang cố gắng để bình thường hóa mỗi hàng như vậy mà nó độ lớn là một (tức là đơn vị chiều dài của một hàng là một hoặc tổng của bình phương của mỗi phần tử trong một hàng là một):

import numpy as np 

a = np.arange(0,27,3).reshape(3,3) 

result = a/np.linalg.norm(a, axis=-1)[:, np.newaxis] 
# array([[ 0.  , 0.4472136 , 0.89442719], 
#  [ 0.42426407, 0.56568542, 0.70710678], 
#  [ 0.49153915, 0.57346234, 0.65538554]]) 

Xác minh:

np.sum(result**2, axis=-1) 
# array([ 1., 1., 1.]) 
+0

Trục dường như không phải là tham số cho np.linalg.norm (nữa?). – Ztyx

+0

Nó hoạt động trong python 2.7. – walt

+0

Đáng chú ý là điều này tương ứng với định mức l2 (trong đó các hàng tổng hợp thành 1 tương ứng với định mức l1) – dpb

1

nó xuất hiện rằng điều này cũng làm việc

def normalizeRows(M): 
    row_sums = M.sum(axis=1) 
    return M/row_sums 
0

Hoặc sử dụng chức năng lambda, như

>>> vec = np.arange(0,27,3).reshape(3,3) 
>>> import numpy as np 
>>> norm_vec = map(lambda row: row/np.linalg.norm(row), vec) 

mỗi vector của vec sẽ có một chuẩn mực đơn vị.

0

Bạn cũng có thể sử dụng ma trận chuyển vị:

(a.T/row_sums).T 
Các vấn đề liên quan