2016-06-13 13 views
5

Używam np.einsum pomnożyć tabele prawdopodobieństwa jak:Czy mogę użyć więcej niż 26 liter w "numpy.einsum"?

np.einsum('ijk,jklm->ijklm', A, B) 

Problem jest, że mam do czynienia z ponad 26 zmiennych losowych (osie) Ogólnie więc jeśli przypisać każdej zmiennej losowej do nas zabrakło mi listy. Czy istnieje inny sposób, w jaki mogę określić powyższą operację, aby uniknąć tego problemu, bez uciekania się do bałaganu w operacjach np.sum i ?

+0

Można je układać w stosy, aby utworzyć * grubą macierz *? – Divakar

+0

@Divakar przepraszam, co przez to rozumiesz? – akxlr

+0

Nigdy nie myśl o poprzednim komentarzu. Czy masz na myśli wymiary lub zmienne "26"? Jeśli chodzi tylko o zmienne, to nie ma to nic wspólnego z 'einsum', prawda? Te 'ijk' itp.reprezentują wymiary, natomiast "A" jest nazwą zmiennej. Zawsze możesz mieć więcej zmiennych o nazwach "AA", "A2" itd. – Divakar

Odpowiedz

2

Jeśli mówisz o literach ijk w twoim przykładzie i masz więcej niż dostępne znaki alfabetu, to nie, nie możesz.

W kodzie einsum numpy here i here numpy sprawdza każdy znak jeden po drugim z isalpha i wydaje się, że nie ma możliwości utworzenia nazw zawierających więcej niż 1 znak.

Możliwe, że możesz używać wielkich liter, ale główna odpowiedź na to pytanie jest taka, że ​​nie możesz mieć nazw dla osi z więcej niż 1 znakiem.

3

Można użyć formularza einsum(op0, sublist0, op1, sublist1, ..., [sublistout]) zamiast i,j,ik->ijk, w którym interfejs API nie jest ograniczony do 52 osi *. W jaki sposób ten szczegółowy formularz odpowiada formularzowi ijk, pokazano in the documentation.

OP

np.einsum('ijk,jklm->ijklm', A, B) 

zostanie zapisana jako

np.einsum(A, [0,1,2], B, [1,2,3,4], [0,1,2,3,4]) 

(* Uwaga: Realizacjajest nadal ograniczona do 26 osi Zobacz @hpaulj's answer i do wyjaśnienia.)


Równoważność s z przykładów numpy:

>>> np.einsum('ii', a) 
>>> np.einsum(a, [0,0]) 

>>> np.einsum('ii->i', a) 
>>> np.einsum(a, [0,0], [0]) 

>>> np.einsum('ij,j', a, b) 
>>> np.einsum(a, [0,1], b, [1]) 

>>> np.einsum('ji', c) 
>>> np.einsum(c, [1,0]) 

>>> np.einsum('..., ...', 3, c) 
>>> np.einsum(3, [...], c, [...]) 

>>> np.einsum('i,i', b, b) 
>>> np.einsum(b, [0], b, [0]) 

>>> np.einsum('i,j', np.arange(2)+1, b) 
>>> np.einsum(np.arange(2)+1, [0], b, [1]) 

>>> np.einsum('i...->...', a) 
>>> np.einsum(a, [0, ...], [...]) 

>>> np.einsum('ijk,jil->kl', a, b) 
>>> np.einsum(a, [0,1,2], b, [1,0,3], [2,3]) 
+0

Powoduje błąd, jeśli indeks wynosi> 52; a z powodu błędu nie działa poprawnie dla indeksu> 26. – hpaulj

+0

@hpaulj: Dzięki, zaktualizowany. Szczerze mówiąc einsum powinno zostać wdrożone poprzez przekształcenie formy 'ijk' w bardziej ogólną i strukturalną alternatywną składnię, a nie odwrotnie. – kennytm

+0

Dobrze jest wzorowane na równaniach, które fizycy piszą, a na końcu są tłumaczone na listę "op_axis" list, które pokazuję. Argumenty łańcuchowe były również używane w klasach "klasy indeksowania". – hpaulj

5

Krótka odpowiedź brzmi: możesz użyć dowolnej z 52 liter (górnej i dolnej). To wszystkie litery w języku angielskim. Wszelkie nazwy hodowców osi będą musiały być odwzorowane na tych 52 lub równoważny zestaw liczb. Praktycznie mówiąc, będziesz chciał użyć ułamka tych 52 w jednym połączeniu einsum.


sugeruje użycie alternatywnej składni wejściowej. Kilka próbnych przebiegów sugeruje, że nie jest to rozwiązanie. 26 nadal jest praktycznym limitem (pomimo podejrzanych komunikatów o błędach).

In [258]: np.einsum(np.ones((2,3)),[0,20],np.ones((3,4)),[20,2],[0,2]) 
Out[258]: 
array([[ 3., 3., 3., 3.], 
     [ 3., 3., 3., 3.]]) 

In [259]: np.einsum(np.ones((2,3)),[0,27],np.ones((3,4)),[27,2],[0,2]) 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-259-ea61c9e50d6a> in <module>() 
----> 1 np.einsum(np.ones((2,3)),[0,27],np.ones((3,4)),[27,2],[0,2]) 

ValueError: invalid subscript '|' in einstein sum subscripts string, subscripts must be letters 

In [260]: np.einsum(np.ones((2,3)),[0,100],np.ones((3,4)),[100,2],[0,2]) 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-260-ebd9b4889388> in <module>() 
----> 1 np.einsum(np.ones((2,3)),[0,100],np.ones((3,4)),[100,2],[0,2]) 

ValueError: subscript is not within the valid range [0, 52] 

Nie jestem do końca pewien, dlaczego trzeba więcej niż 52 liter (dużych i małych liter), ale na pewno trzeba zrobić jakąś mapowania. Nie chcesz napisać ciągu znaków einsum używając więcej niż 52 osi naraz. Wynikowy iterator byłby zbyt duży (dla pamięci lub czasu).

jestem wyobrażając jakąś funkcję mapowania, który może być używany jako:

astr = foo(A.names, B.names) 
# foo(['i','j','k'],['j','k','l','m']) 
# foo(['a1','a2','a3'],['a2','a3','b4','b5']) 
np.einsum(astr, A, B) 

https://github.com/hpaulj/numpy-einsum/blob/master/einsum_py.py

jest wersja Pythona z einsum. Mówiąc prościej, einsum analizuje ciąg znaków dolnych, tworząc listę op_axes, która może być użyta w np.nditer do ustawienia wymaganej kalkulacji sumy produktów. Z tym kodem mogę patrzeć na to, jak tłumaczenie jest zrobione:

Od przykład w bloku __name__:

label_str, op_axes = parse_subscripts('ik,kj->ij', Labels([A.ndim,B.ndim])) 
    print op_axes 
    # [[0, -1, 1], [-1, 1, 0], [0, 1, -1]] fine 
    # map (4,newaxis,3)(newaxis,3,2)->(4,2,newaxis) 
    print sum_of_prod([A,B],op_axes) 

swoim przykładzie, z pełnym wyjściu diagnostycznym jest

In [275]: einsum_py.parse_subscripts('ijk,jklm->ijklm',einsum_py.Labels([3,4])) 
jklm 
{'counts': {105: 1, 106: 2, 107: 2, 108: 1, 109: 1}, 
'strides': [], 
'num_labels': 5, 
'min_label': 105, 
'nop': 2, 
'ndims': [3, 4], 
'ndim_broadcast': 0, 
'shapes': [], 
'max_label': 109} 
[('ijk', [105, 106, 107], 'NONE'), 
('jklm', [106, 107, 108, 109], 'NONE')] 
('ijklm', [105, 106, 107, 108, 109], 'NONE') 
iter labels: [105, 106, 107, 108, 109],'ijklm' 
op_axes [[0, 1, 2, -1, -1], [-1, 0, 1, 2, 3], [0, 1, 2, 3, 4]] 

Out[275]: 
(<einsum_py.Labels at 0xb4f80cac>, 
[[0, 1, 2, -1, -1], [-1, 0, 1, 2, 3], [0, 1, 2, 3, 4]]) 

Korzystanie 'ajk,jkzZ->ajkzZ' zmian etykiety, ale powoduje to samo op_axes.


Oto pierwszy szkic funkcji tłumaczenia. Powinno to działać na każdej liście list (z hashable pozycji):

def translate(ll): 
    mset=set() 
    for i in ll: 
     mset.update(i) 
    dd={k:v for v,k in enumerate(mset)} 
    x=[''.join([chr(dd[i]+97) for i in l]) for l in ll] 
    # ['cdb', 'dbea', 'cdbea'] 
    y=','.join(x[:-1])+'->'+x[-1] 
    # 'cdb,dbea->cdbea' 

In [377]: A=np.ones((3,1,2),int) 
In [378]: B=np.ones((1,2,4,3),int) 
In [380]: ll=[list(i) for i in ['ijk','jklm','ijklm']] 
In [381]: y=translate(ll) 
In [382]: y 
Out[382]: 'cdb,dbea->cdbea' 

In [383]: np.einsum(y,A,B).shape 
Out[383]: (3, 1, 2, 4, 3) 

Zastosowanie set mapować obiekty indeksu oznacza, że ​​końcowe znaki indeksujące są nieuporządkowane. Tak długo jak określasz RHS, który nie powinien być problemem. Zignorowałem też ellipsis.

=================

Wersja lista einsum wejścia przekształcono w wersji dolny ciąg w einsum_list_to_subscripts() (w numpy/core/src/multiarray/multiarraymodule.c). Zastępuje on znak ELLIPSIS za pomocą "...". Podniósł [0,52] komunikat o błędzie, jeśli (s < 0 || s > 2*26) gdzie s jest liczbą w jednej z tych podlist. I konwertuje s na ciąg z

 if (s < 26) { 
      subscripts[subindex++] = 'A' + s; 
     } 
     else { 
      subscripts[subindex++] = 'a' + s; 

Ale wygląda na to, że drugi przypadek nie działa; Otrzymuję błędy podobne do 26.

ValueError: invalid subscript '{' in einstein sum subscripts string, subscripts must be letters 

To 'a'+s jest źle, jeśli s>26:

In [424]: ''.join([chr(ord('A')+i) for i in range(0,26)]) 
Out[424]: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 

In [425]: ''.join([chr(ord('a')+i) for i in range(0,26)]) 
Out[425]: 'abcdefghijklmnopqrstuvwxyz' 

In [435]: ''.join([chr(ord('a')+i) for i in range(26,52)]) 
Out[435]: '{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94' 

To 'a'+s jest źle; to powinno być:

In [436]: ''.join([chr(ord('a')+i-26) for i in range(26,52)]) 
Out[436]: 'abcdefghijklmnopqrstuvwxyz' 

złożyłam https://github.com/numpy/numpy/issues/7741

istnienia tego błędu po całym tym czasie wskazuje, że format podlistę nie jest powszechne, a to za pomocą dużej ilości w tym wykazie jest jeszcze rzadsze.

Powiązane problemy