2012-07-05 31 views
6

Tôi có numpy.array s trong đó các cột chứa các kiểu dữ liệu khác nhau và các cột cũng phải có các hàm khác nhau được áp dụng cho chúng. Tôi cũng có các hàm trong một mảng.Numpy: Áp dụng một mảng các hàm cho cùng một mảng có độ dài 2d như thể nhân yếu tố? (sử dụng hàm python làm toán tử?)

Hãy nói rằng:

a = array([[ 1, 2.0, "three"], 
      [ 4, 5.0, "six" ]], dtype=object) 

functions_arr = array([act_on_int, act_on_float, act_on_str]) 

tôi chắc chắn có thể nghĩ ra cách để làm điều này bằng cách chia điều, nhưng có một điều mà dường như tự nhiên nhất đối với tôi là để suy nghĩ về nó như một nhân elementwise với phát sóng, và các chức năng như các toán tử. Vì vậy, tôi muốn làm một cái gì đó giống như

functions_arr*a 

và nhận được ảnh hưởng của

array([[act_on_int(1), act_on_float(2.0), act_on_str("three")], 
     [act_on_int(4), act_on_float(5.0), act_on_str("six") ]]) 

Bạn có biết một cách để đạt được một cái gì đó dọc theo những đường?

Chỉnh sửa: Tôi đã thay đổi định nghĩa của mảng trong câu hỏi để bao gồm dtype=[object] khi mọi người chỉ ra điều này quan trọng đối với mảng lưu trữ các loại theo cách tôi dự định.

Cảm ơn câu trả lời và nhận xét của bạn! Tôi đã chấp nhận người gửi trả lời và cảm thấy điều này là rất gần với những gì tôi đã có trong tâm trí.

Vì có vẻ như đã có một số nhầm lẫn về cách tôi xem xét các hoạt động được như nhân, hãy để tôi làm rõ rằng với một ví dụ khác:

Như bạn cũng biết, một hoạt động như:

v = array([1,2,3]) 
u = array([[5,7,11], 
      [13,17,19]]) 
v*u 

sẽ phát sóng v trên các hàng của u và mang lại

array([[ 1*5, 2*7, 3*11], 
     [1*13, 2*17, 3*19]]) 

tức

array([[ 5, 14, 33], 
     [13, 34, 57]]) 

Nếu bây giờ chúng tôi đã thay thế v với ví dụ các del operator chúng ta sẽ có (sau đây là không thực sự làm việc mã python :)

V = array([(d/dx),(d/dy),(d/dz)]) 
u = array([[5,7,11], 
      [13,17,19]]) 
V*u 

năng suất (trong tinh thần)

array([[(d/dx)5, (d/dy)7, (d/dz)11]], 
     [(d/dx)13,(d/dy)17,(d/dz)19]]) 

Tôi thừa nhận lấy đạo hàm của một loạt các hằng số sẽ không phải là số nhiều nhất thú vị về hoạt động, do đó, hãy thay thế u bằng một số biểu thức toán học biểu tượng trong x, yz. Ở mức nào, tôi hy vọng điều này ít nhất làm cho rõ ràng hơn cả lý luận của tôi và bit về "(sử dụng một hàm python như một toán tử?)" Trong tiêu đề.

Trả lời

2

Như Sven Marnach nhắc nhở tôi, mảng bạn đã tạo có lẽ là một mảng của các đối tượng Python. Bất kỳ hoạt động nào trên chúng có thể sẽ chậm hơn nhiều so với các hoạt động thuần túy numpy. Tuy nhiên, bạn có thể làm những gì bạn đã yêu cầu khá dễ dàng, miễn là bạn không thực sự mong đợi điều này là rất nhanh! Nó không quá khác biệt so với những gì AFoglia gợi ý, nhưng đó là điều để trở thành chính xác những gì bạn yêu cầu:

>>> a = numpy.array([[ 1, 2.0, "three"], 
...     [ 4, 5.0, "six" ]], dtype=object) 
>>> funcs = [lambda x: x + 10, lambda x: x/2, lambda x: x + '!'] 
>>> apply_vectorized = numpy.vectorize(lambda f, x: f(x), otypes=[object]) 
>>> apply_vectorized(funcs, a) 
array([[11, 1.0, three!], 
     [14, 2.5, six!]], dtype=object) 

Cũng lặp lại AFoglia ở đây, có một cơ hội tốt bạn muốn được tốt hơn bằng cách sử dụng một mảng kỷ lục - điều này cho phép bạn chia mảng theo ý muốn, và làm việc với nó theo cách tự nhiên hơn bằng cách sử dụng một cách tự nhiên hơn bằng cách sử dụng các hàm Python một cách tự nhiên hơn, thường là:

rec.array([(1, 2.0, 'three'), (4, 5.0, 'six')], 
     dtype=[('int', '<i8'), ('float', '<f8'), ('str', '|S10')]) 
>>> a['int'] 
array([1, 4]) 
>>> a['float'] 
array([ 2., 5.]) 
>>> a['str'] 
rec.array(['three', 'six'], 
     dtype='|S10') 
>>> a['int'] += 10 
>>> a['int'] 
array([11, 14]) 
3

bạn đang tìm kiếm chức năng built-in zip()

Một ví dụ đơn giản sử dụng lists:

>>> a=[[ 1, 2.0, "three"],[ 4, 5.0, "six" ]] 

>>> funcs=[lambda x:x**2,lambda y:y*2,lambda z:z.upper()] 

>>> [[f(v) for v,f in zip(x,funcs)]for x in a] 
[[1, 4.0, 'THREE'], [16, 10.0, 'SIX']] 
+3

Tôi không nghĩ điều này trả lời câu hỏi. OP hỏi làm thế nào để có được phát sóng trong tình huống này. Mã này không phát sóng. –

3

Nó không phát sóng, bởi vì các mảng ban đầu chỉ có một chiều. Dường như nó có 2 chiều bởi vì mỗi phần tử có ba thành viên (một int, một phao và một chuỗi), nhưng để gọn gàng, đó chỉ đơn giản là kiểu và số thứ nguyên là một.

Cũng không phải là phép nhân, bởi vì bạn đang áp dụng hàm cho từng phần tử. (Không còn phép nhân nào ngoài việc thêm vào, do đó, functions_arr * a là cú pháp gây hiểu lầm.)

Tuy nhiên, bạn có thể viết một cái gì đó tương tự như những gì bạn muốn. Tôi muốn thử numpy.vectorize. Nếu không thử nghiệm nó, và giả định dtype đầu ra là giống như mảng ban đầu. Tôi tưởng tượng nó sẽ giống như ...

def act_on_row(row) : 
    return (act_on_int(row["int_field"]), 
      act_on_float(row["float_field"]), 
      act_on_str(row["str_field"])) 

act_on_array = numpy.vectorize(act_on_row, otypes=[a.dtype]) 

acted_on = act_on_array(a) 

Tôi chưa bao giờ thử vectorize, và tôi không biết có khó khăn khi làm việc với dtypes có cấu trúc hay không nhưng điều này sẽ giúp bạn bắt đầu.

Giải pháp đơn giản hơn là chỉ lặp qua mảng theo trường.

rslt = numpy.empty((len(a),), dtype=a.dtype) 

rslt["int_field"] = act_on_int(a["int_field"]) 
rslt["float_field"] = act_on_float(a["float_field"]) 
rslt["str_field"] = act_on_str(a["str_field"]) 

(Bạn có thể cần phải vectorize từng chức năng riêng biệt, tùy thuộc vào những gì họ làm.)

+1

Mảng 'a' như được định nghĩa trong bài gốc là mảng hai chiều và * không * mảng có cấu trúc một chiều. (Bạn có thể tranh luận OP * nên * thực sự đang sử dụng một mảng có cấu trúc, mặc dù.) –

+0

@SvenMarnach, đúng vậy; nhưng thậm chí là _possible_ có một mảng 2 chiều thực sự với các kiểu dữ liệu không đồng nhất? Tôi sẽ đề xuất một biến thể về câu trả lời này, nhưng không thể hiểu được cách tạo ra những gì mà OP tuyên bố đã tạo ra. Tôi đã từng sử dụng các mảng có cấu trúc/bản ghi cho mục đích đó. – senderle

+1

@senderle: Tôi nghĩ rằng mã được đưa ra bởi OP sẽ chỉ đơn giản là tạo ra một mảng các chuỗi có độ rộng cố định. Bạn có thể tạo một mảng không đồng nhất bằng cách sử dụng 'dtype = object', cho phép các đối tượng Python tùy ý làm các mục mảng. Tuy nhiên, điều này sẽ vô hiệu hóa hầu hết các lợi ích về hiệu suất và bộ nhớ của NumPy - các mảng như vậy có thể được mô tả như các danh sách Python có kích thước cố định, đa chiều. –

Các vấn đề liên quan