2016-06-13 14 views
5

I np.einsum bin mit Wahrscheinlichkeitstabellen dergleichen zu multiplizieren:Kann ich mehr als 26 Buchstaben in `numpy.einsum` verwenden?

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

Das Problem ist, dass ich insgesamt bin Umgang mit höchstens 26 Zufallsvariablen (Achsen), also wenn ich jedes Zufallsvariable einen Brief zuweisen I ausgehen Briefe. Gibt es eine andere Möglichkeit, die obige Operation anzugeben, um dieses Problem zu vermeiden, ohne auf ein Durcheinander von np.sum und np.dot Operationen zurückgreifen zu müssen?

+0

Sie können sie wahrscheinlich zu einem * fetten Array * stapeln? – Divakar

+0

@Divakar Entschuldigung, was meinst du damit? – akxlr

+0

Vergiss den vorherigen Kommentar. Meinst du 26 Dimensionen oder Variablen? Wenn es nur um Variablen geht, dann hat das nichts mit'Einsum' zu tun, oder? Diese "ijk" usw.repräsentieren die Dimensionen, während 'A' der Variablenname ist. Sie können immer mehr Variablen mit Namen wie 'AA', 'A2' usw. haben. – Divakar

Antwort

2

Wenn Sie über die Buchstaben ijk in Ihrem Beispiel sprechen und mehr als die verfügbaren Buchstaben haben, dann können Sie nicht.

Im einsum numpy Code here und here numpy prüft jedes Zeichen einzeln mit isalpha und es scheint keine Möglichkeit zu geben Namen zu schaffen, mit mehr als 1 Zeichen.

Vielleicht können Sie Großbuchstaben verwenden, aber die Hauptantwort auf die Frage ist, dass Sie keine Namen für die Achsen mit mehr als 1 Zeichen haben können.

3

Sie könnten das einsum(op0, sublist0, op1, sublist1, ..., [sublistout]) Formular anstelle von i,j,ik->ijk verwenden, wobei die API nicht auf 52 Achsen * beschränkt ist. Wie diese verbose Form der ijk-Form entspricht, wird gezeigt in the documentation.

OPs

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

als

geschrieben würde
np.einsum(A, [0,1,2], B, [1,2,3,4], [0,1,2,3,4]) 

(* Hinweis: Die Implementierung ist noch zu 26 Achsen beschränkt Siehe @hpaulj's answer und zur Erläuterung.)


Äquivalenz s aus numpys Beispielen:

>>> 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

Es wird ein Fehler gemeldet, wenn der Index> 52 ist. und aufgrund des Fehlers funktioniert nicht richtig für den Index> 26. – hpaulj

+0

@hpaulj: Danke, aktualisiert. Offen gesagt sollte einsum implementiert werden, indem die 'ijk'-Form in die allgemeinere und strukturierte alternative Syntax transformiert wird, und nicht umgekehrt. – kennytm

+0

Nun, es ist nach den Gleichungen, die Physiker schreiben, modelliert und wird schließlich in die "op_axis" Liste von Listen übersetzt, die ich zeige. String-Argumente wurden auch in "indexing_tricks" -Klassen verwendet. – hpaulj

5

Die kurze Antwort ist, können Sie einen der 52 Buchstaben (oben und unten) verwenden. Das sind alle Buchstaben in der englischen Sprache. Alle feineren Achsennamen müssen auf diesen 52 oder einem äquivalenten Zahlensatz abgebildet werden. Praktisch gesprochen wollen Sie einen Bruchteil dieser 52 in einem beliebigen einsum Anruf verwenden.


@kennytm schlägt die alternative Eingabesyntax. Ein paar Stichproben deuten darauf hin, dass dies keine Lösung ist. 26 ist immer noch das praktische Limit (trotz der verdächtigen Fehlermeldungen).

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] 

Ich bin nicht ganz sicher, warum Sie mehr als 52 Buchstaben (Groß- und Kleinschreibung) benötigen, aber ich bin sicher, Sie brauchen eine Art von Mapping zu tun. Sie möchten keinen einsum String mit mehr als 52 Achsen auf einmal schreiben. Der resultierende Iterator wäre zu groß (für Speicher oder Zeit).

Ich bin eine Art von Abbildungsfunktion abbildet, die als verwendet werden können:

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

ist eine Python-Version von einsum. Grob gesagt analysiert einsum die Indexzeichenfolge und erstellt eine op_axes Liste, die in np.nditer verwendet werden kann, um die erforderliche Berechnung der Summe der Produkte einzurichten. Mit diesem Code kann ich sehen, wie die Übersetzung fertig ist:

Von einem Beispiel im __name__ Block:

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) 

Ihr Beispiel mit vollem Diagnoseausgang ist

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]]) 

Mit 'ajk,jkzZ->ajkzZ' Änderungen Etiketten, aber Ergebnisse in der gleichen op_axes.


Hier ist ein erster Entwurf einer Übersetzungsfunktion. Es sollte für jede Liste von Listen (von hashable Artikel) arbeiten:

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) 

Die Verwendung von set Indexobjekte abzubilden bedeutet, dass die endgültige Indizierung Zeichen ungeordnete sind. Solange Sie die RHS angeben, die kein Problem sein sollte. Auch ich ignorierte ellipsis.

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

Die Liste Version von einsum Eingabe in den Index String-Version in einsum_list_to_subscripts() (in numpy/core/src/multiarray/multiarraymodule.c) umgewandelt wird. Es ersetzt ELLIPSIS durch '...'. Es wurde die Fehlermeldung [0,52] ausgelöst, wenn (s < 0 || s > 2*26)s eine Nummer in einer dieser Unterlisten ist. Und wandelt s bespannen mit

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

Aber es sieht aus wie der zweite Fall nicht funktioniert; Ich bekomme Fehler wie für 26.

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

Das 'a'+s ist falsch, wenn 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' 

Das 'a'+s ist falsch; ist sein sollte:

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

I eingereicht https://github.com/numpy/numpy/issues/7741

Die Existenz dieses Fehlers nach all dieser Zeit zeigt an, dass das sublist Format nicht üblich ist, und dass in dieser Liste eine große Anzahl verwendet, ist noch seltener.

Verwandte Themen