Выходные данные np.outer изменяются при сохранении в массиве - PullRequest
0 голосов
/ 15 февраля 2020

У меня есть матрица NxN, которую я заинтересован в ее разложении по собственным значениям для получения P = exp (tA). Чтобы оценить функции P_ij (t), я хочу подготовить матрицу E = NxNxN, где E - внешнее произведение v [i], а np.linalg.inv(v)[i] и v[i] - один из собственных векторов.

Пример кода с моей игрушечной матрицей 3x3:

def eig_trial(A,n):
        v,w=np.linalg.eig(A)
        w_inv=np.linalg.inv(
        eigs=np.array([[[0 for k in xrange(len(v))] for j in xrange(n)] for i in xrange(n)])
        for i in range(len(v)):
            q=np.outer(np.array(w[:,i]),np.array(w_inv[i]))
            eigs[i]=q            
        pprint.pprint(eigs)


A=np.asarray([[6,3,-2],[-4, -1, 2],[13,9,-3]])
eig_trial(A,3)

Проблема в том, что q=np.outer(...), что является правильным значением, не равно eigs[i].

Есть ли причина, почему я не могу сохранить это в матрице? Если это помогает, я использую версию Canopy: 2.1.9.3717 (64 бит) и Python 2.7.13.

Спасибо!

Ответы [ 2 ]

1 голос
/ 15 февраля 2020

Проблема в том, что инициализируемый вами массив eigs имеет dtype int

In [96]: alist = ([[0 for k in range(5)] for j in range(3)])                                   
In [97]: arr = np.array(alist)                                                                 
In [98]: alist                                                                                 
Out[98]: [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
In [99]: arr                                                                                   
Out[99]: 
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])

и выполняет некоторые назначения:

In [100]: arr[0] = np.arange(5)                                                                
In [101]: alist[0] = np.arange(5)                                                              
In [102]: arr[1] = np.arange(5)*.1                                                             
In [103]: alist[1] = np.arange(5)*.1                                                           

arr все еще целые числа, несмотря на то, что последнее присваивание включает в себя числа с плавающей точкой

In [104]: arr                                                                                  
Out[104]: 
array([[0, 1, 2, 3, 4],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])
In [105]: alist                                                                                
Out[105]: [array([0, 1, 2, 3, 4]), array([0. , 0.1, 0.2, 0.3, 0.4]), [0, 0, 0, 0, 0]]

Вы можете увидеть усечение более четко с помощью:

In [108]: arr[1] = np.arange(5)*1.3                                                            
In [109]: arr                                                                                  
Out[109]: 
array([[0, 1, 2, 3, 4],
       [0, 1, 2, 3, 5],
       [0, 0, 0, 0, 0]])

Если массив начинался как float dtype:

    In [110]: arr = np.zeros((3,5))  # float dtype default                                         
    In [111]: arr[0] = np.arange(5)                                                                
    In [112]: arr[1] = np.arange(5)*1.3                                                            
    In [113]: arr                                                                                  
    Out[113]: 
    array([[0. , 1. , 2. , 3. , 4. ],
           [0. , 1.3, 2.6, 3.9, 5.2],
           [0. , 0. , 0. , 0. , 0. ]])

Вы могли бы также инициализировать eigs с 0. вместо 0

In [114]: np.array([0. for _ in range(5)])                                                     
Out[114]: array([0., 0., 0., 0., 0.])

, но zeros, который я использовал выше, быстрее (и проще)

Вы не сделали Необходимо назначить всю вложенную глубину списка. Просто первого слоя было бы достаточно. Списку можно присвоить что угодно:

In [115]: alist = [None for _ in range(5)]                                                     
In [116]: alist                                                                                
Out[116]: [None, None, None, None, None]
In [117]: alist[0] = np.arange(5)                                                              
In [118]: alist[1] = 32                                                                        
In [119]: alist[2] = np.ones((3,2))                                                            
In [120]: alist                                                                                
Out[120]: 
[array([0, 1, 2, 3, 4]), 32, array([[1., 1.],
        [1., 1.],
        [1., 1.]]), None, None]

Назначение массива arr[0] = np.arange(5) отличается. Там подразумевается arr[0,:,:] = .... Если выбранный слот в arr не совпадает с массивом RHS, вы получите ошибку. match означает либо точное совпадение по форме, либо совпадение по условиям вещания.

Когда вы столкнетесь с подобными проблемами, поэкспериментируйте с небольшими частями кода, как я демонстрирую. Гораздо проще отследить проблемы с помощью небольших интерактивных примеров.

0 голосов
/ 15 февраля 2020

Я буквально понятия не имею, но я нашел странный обходной путь. Проблема в том, что eigs является массивом. Это работает, если это список списков.

def eig_trial(A,n):
        v,w=np.linalg.eig(A)
        w_inv=np.linalg.inv(
        eigs=[[[0 for k in xrange(len(v))] for j in xrange(n)] for i in xrange(n)] #np.array dropped
        for i in range(len(v)):
            q=np.outer(np.array(w[:,i]),np.array(w_inv[i]))
            eigs[i]=q
        eigs=np.asarray(eigs) #now convert it to an np array
        pprint.pprint(eigs)


A=np.asarray([[6,3,-2],[-4, -1, 2],[13,9,-3]])
eig_trial(A,3)

Я был бы очень рад, если бы кто-то объяснил почему, но это по крайней мере решение.

...