Datentyp Slicing-Notation

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

Ich habe eine Frage zu folgendem Problem:

[codebox=pys60 file=Unbenannt.txt]
import numpy as np
l=[5,6,7,8,9]
a=np.arange(12).reshape(3,4)

l[1]
a[1]
a[2,2]

var1=1
var2=2,2

l[var1]
a[var1]
a[var2]

l[1:3]
l[::2]
a[:3,1:3]
a[:,0]
a[::2,::2]

[/code]

Ich kann also mit Hilfe von Variablen auf den Index einer Liste oder Tabelle zugreifen (Zeile 12-14). Kann ich mir auch eine Variable bzw einen Datentyp definieren, mit denen ich einen Slicing Zugriff wie in Zeile 16-20 darstellen kann (z.B. var_slice=("1:3"); l[var_slice]). Dieses wäre sehr hilfreich, um beispielsweise gleiche Aktionen wahlweise für Zeilen oder Spalten durchzuführen ohne mit if-Konstruktionen Fallunterscheidungen machen zu müssen. Aber auch wenn auf mehrere Arrays mit gleichen Subindizes zugegriffen werden soll ,bräuchte man nicht jedes Mal zu schreiben arr3 = arr1[Variablenname1:Variablenname2,Variablenname3:Variablenname4] == arr2[Variablenname1:Variablenname2,Variablenname3:Variablenname4], sondern käme mit einem arr3 = arr1[var_slice] == arr2[var_slice] aus. Bei noch höhreren Dimensionen wird es immer unübersichtlicher (5 Dimensionen entspricht bis zu 15 Parameter)
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

Danke für die schnelle Antwort. Tipp ist schon hilfreich. Verstehe ich es richtig, daß ich dann für ein n-dimensionales Array nicht mehr bis zu n*3 Parameter benötige, sondern nur noch n Parameter. Auf einen Parameter, der alles beinhaltet kann ich es aber nicht reduzieren?.
BlackJack

@Siegfried: Doch natürlich: es gibt dort immer nur einen Parameter. Falls Du denkst das beispielsweise ``a[:3,1:3]`` zwei Parameter sind, dann irrst Du Dich. Das ist *ein* Tupel mit zwei Slices das da in den eckigen Klammern steht. Also äquivalent zu ``a[slice(0, 3), slice(1, 3)]`` beziehungsweise ``ix = slice(0, 3), slice(1, 3); a[ix]``.

Edit: Und falls Du irgendwo in der []-Syntax die drei Auslassungspunkte verwendest (``a[5,...]``): das ist ausserhalb der speziellen Syntax das `Ellipsis`-Objekt, also ``ix = 5, Ellipsis; a[ix]``.
Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

@BlackJack: Das es sich um ein Tupel handelt war mir klar (siehe ursprüngliche Programmzeilen 10 und 14). Ich habe meine Frage nicht präzise genug formuliert und versuche es mit folgendem Beispiel.

[codebox=pys60 file=Unbenannt.txt]
import numpy as np

def ausgabe(parameter):
arr = np.arange(12).reshape(3,4)
print arr[parameter]

sleis1=slice(1,2)
sleis2=slice(0,2)
ausgabe(sleis1)
ausgabe((sleis1,sleis2))

[/code]

Ich kann also Zeilen, Subarrays und einzelnde Elemente ausgeben. Was mache ich aber, wenn ich nur eine oder mehrere Spalten haben möchte (zB arr[:,2:3]) :?:
BlackJack

@Siegfried: Da gibt es keinen Unterschied:

Code: Alles auswählen

In [14]: ausgabe((slice(None), slice(2, 3)))
[[ 2]
 [ 6]
 [10]]
Oder habe ich die Frage immer noch nicht richtig verstanden? :-)
Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

@BlackJack: Asche auf mein Haupt :oops: . Auf slice(None) muß man erst mal kommen. Danke nochmals, auch an __deets__, für Eure superschnellen und kompetenten Antworten.
Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

Ein Unterschied zwischen den Notationen ist mir aber doch ausgefallen:
[codebox=pys60 file=Unbenannt.txt]
a=np.arange(12).reshape(3,4)
a[1]
a[slice(1,2)]

[/code]

Dabei liefert der Ausdruck in Zeile 2 ein eindimensionales Array zurück, während der Ausdruck in Zeile 3 ein zweidimensionales Array als Ergebnis ausgibt.
BlackJack

@Siegfried: Ja. a[1] und a[1:2] ist nicht das gleiche. Das hat aber auch hoffentlich niemand behauptet. :-) Das eine sagt: Gib mir das Element an Stelle 1, und das andere sagt gib mir die Sequenz mit den Elementen von 1 bis 2 (exklusive).
Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

@BlackJack: Wohl wahr, aber mir ist es nicht möglich mit der slice() Funktion ein eindimensionales Array als Ergebnis zu erhalten.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

naja, du musst ja in dem Moment auch kein slice-Objekt nehmen, sondern nur eine Zahl. Aufbauend auf deinem Beispiel:

Code: Alles auswählen

>>> c = (1,)
>>> a[c]
array([4, 5, 6, 7])
>>> c = slice(1)
array([[0, 1, 2, 3]])
Das ist halt eine Unterscheidung, die syntaktisch auch gemacht wird. Kein slicing-Operator, dann kein slice.
Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

@__deets__: In Deinem Beispiel fehlt als vorletzte Zeile a[c]. Aber Dein Beispiel zeigt ja gerade, daß sich ein zweidimenionales Array ergibt. Wie ich in meinem ursprünglichen Beitrag schrieb, geht es darum, einer Funktion die Indizes in slice()-Form zu übergeben, damit sie beispielsweise list comprehensions mit der Zeile/Spalte machen kann. Beispiel:
[codebox=pys60 file=Unbenannt.txt]
def f(sliceindex):
a=np.arange(12).reshape(3,4)
print [i * i for i in a[sliceindex]]

f((slice(1,2),slice(None)))
f((slice(None),slice(1,2)))
[/code]

Dabei kommen eben unerwartete Ergebnisse, da durch die slice()-Funktion immer ein zweidimensionales Array entsteht

Ähnliches gilt, wenn man Teilarrays, die durch slice() gebildet wurden, übergibt, um in der Funktion damit irgendetwas zu machen. es werden immer zweidimensionale Arrays übergeben.
BlackJack

@Siegfried: Das sind keine unerwarteten Ergebnisse. Denn so funktionieren Slices nun mal. Und es wäre *wirklich* unerwartet wenn alle Slices eine Sequenz liefern *ausser* wenn das Slice nur ein Element lang ist. *Das* wäre eine *echt* blöde API.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Stimmt, die Zeile fehlt.

Ich verstehe deinen Punkt aber nicht. Es geht doch darum, flexibel auf die Array zuzugreifen. Es ist halt zu unterscheiden, ob du einen slice willst, oder eine Zeile. a[1] ist halt was anderes als a[1:2]

Und das kannst du doch darstellen. Ohne das du an der verwendungsseite zB eine falluntescheidung einbauen müsstest. Du musst halt auf der definitionsseite schon wissen, was du willst.
Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

@BlackJack, @__deets__: Danke nochmals für Eure Antworten. Ich verstehe,was Ihr mir sagen wollt. Natürlich sollen nicht alle Slices eine Sequenz liefern und selbstverständlich ist a[1] etwas anderes als a[1:1]. Die Frage war ja: Kann ich a[1] oder a[:,2] durch slice() Notation nachbilden?
Siegfried
User
Beiträge: 24
Registriert: Sonntag 30. April 2017, 14:04

Jetzt hab ich es! Ich hatte zu kompliziert gedacht. Bei StackOverflow habe ich lolgende Klasse gefunden.


[codebox=pys60 file=Unbenannt.txt]
>>> class slicee:
... def __getitem__(self, item):
... return `item`
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
[/code]

"slicee" ruft danach ausprobiert zu werden und beantwortet alle Fragen!
Antworten