array an anderes anhängen - append

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Krischu
User
Beiträge: 95
Registriert: Dienstag 14. Januar 2014, 09:07

Ich möchte ein leeres (numpy) array deklarieren, was das shape (,10) hat. Dem Array möchte ich nach und nach Array Zeilen [0,1,2,3,4,5,6,7,8,9] anhängen.

Code: Alles auswählen

import numpy as np

c=np.array([])

b=np.array([0,1,2,3,4,5,6,7,8,9])

np.append(c,b[0])
print (b)
print (c)
EDIT: noch ein weiterer Versuch:

Code: Alles auswählen

import numpy as np

c=np.empty(10,dtype=int)

b=np.array([0,1,2,3,4,5,6,7,8,9])

np.append(c,b[0])
np.append(c,b[0])
print (b)
print (c)

Würde eigentlich erwarten, daß b nun zwei Zeilen
hat. Irgendwie gelingt es mir nicht. Kann jemand helfen? Danke im voraus.
--
Grüße
Christoph
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Krischu: Arrays sind keine Listen — die `append()`-Funktion von `numpy` macht etwas leicht anderes als die `append()`-Methode von Listen. Arrays kann man nicht in der Form verändern, darum kann man an ein Array nichts anhängen, sondern nur ein neues Array erzeugen das aus einer Kopie der beiden zusammengefügten Arrays besteht. Weshalb wiederholt etwas an ein Array anhängen so gar keine gute Idee ist, weil da bei jedem Schritt mehr und mehr Daten im Speicher umkopiert werden müssen.

Wenn man die Grösse des Zielarrays nicht kennt, sammelt man üblicherweise die Teilarrays in einer Liste und verwendet dann `numpy.concatenate()` oder `numpy.vstack()` um die am Ende in ein Gesamtarray zu kopieren.

Edit: Wenn man eine Liste mit Zeilenarrays hat, kann man natürlich auch einfach `numpy.array()` verwenden um daraus ein 2D-Array zu erzeugen.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Krischu
User
Beiträge: 95
Registriert: Dienstag 14. Januar 2014, 09:07

Danke für die Ideen. Genesis der Daten ist folgende:

Code: Alles auswählen



a=p.permutations([6,6,2,2,3,3,7,7,5,5])
<itertools.permutations object at 0x7fca99df6eb8>
# ich könnte jetzt daraus eine Liste machen
b=list(a)

Zunächst habe ich Permutationen von 10 Elementen, die Duplikate enthalten. Daraus folgt, daß die Permutationen auch Duplikate enthalten.

Am liebsten wäre mir von vornherein, ich hätte die Duplikate bereits heraugefiltert.

Wenn ich wüßte, wie ich Duplikate aus einer Liste entferne, wäre ich bereits da. Oder Liste sortiere und unique mache? Oder könnte ich aus `a` gleich ein `set`machen?
--
Grüße
Christoph
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Krischu: Wie wird denn `itertools` zu `p`‽ 😱

Der Iterator liefert Tupel, die kann man direkt in ein `set()` kippen. Und danach in eine Liste sortieren. Und daraus dann ein `numpy.array()` machen. Wenn man da ein Byte pro Element verwendet, könnte man das Beispiel sogar unkomprimiert auf eine Diskette speichern. 😉

Edit: Man könnte auch einfach `more_itertools.distinct_permutations()` verwenden.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Krischu
User
Beiträge: 95
Registriert: Dienstag 14. Januar 2014, 09:07

Danke für den Tip `more_itertools.distinct_permutations()` . Werde ich auch noch ausprobieren. Ansonsten gelöst :

Code: Alles auswählen


import itertools as p
import numpy as np
import math

total = 0

def check(a):
    # hier Code zum überprüfen eine Bedingung
    return True
        
a=p.permutations([3,3,4,4,7,7,1,1,5,5])

# mache aus den Permutationen eine Menge
# damit fallen die Duplikate heraus.
c=set(a)
print(len(c))
# Jetzt machen wir aus dem Set -> List -> Array
b=np.array(list(c))
s=int(b.size/list(b.shape)[1])
print(s,b.shape)
for k in range(s):
    if(check(b[k])):
        total += 1
        print(b[k])
        
print("total=",total)
--
Grüße
Christoph
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Äh, da sind komische Sachen drin. Mal von den besch…eidenen Namen abgesehen. Sinnvolle Namen würden hier vielleicht helfen was Du Dir dabei gedacht hast. Also `s` beispielsweise. Warum teilst Du da die Gesamtzahl der Elemente durch die zweite zweite Dimension? Da kommt bei einem 2D-Array natürlich die erste Dimension bei heraus. Also ``s=int(b.size/list(b.shape)[1])`` ist das gleiche wie ``s=b.shape[0]``. (Es war auch unnötig das `shape`-Tupel in eine Liste umzuwandeln.) Aber auch das geht simpler, denn das ist einfach ``s=len(b)``. Zusammen mit der Schleife haben wir dann das in Python unidiomatische ``for k in range(len(b)):`` wobei `k` hier nur als Index in `b` benutzt wird. W A R U M zu Hölle… Das ist ``for a in b:``.

Da wir eine Prüffunktion haben, liesse sich hier auch sinnvoll `filter()` anwenden.

`total` sollte nicht so weit vor der Schleife mit 0 initialisiert werden. Das vergisst man wahrscheinlich sonst zu entfernen wenn man den Code mit `more_itertools` so umgeschrieben hat, dass man dem Namen gleich das Ergebnis zuweisen kann.

Ich sehe auch nicht warum man hier Numpy braucht solange sich `check()` nicht so schreiben lässt, dass man das auf das ganze Array anwenden kann.

Code: Alles auswählen

from more_itertools import distinct_permutations, ilen, side_effect


def check(a):
    # hier Code zum überprüfen eine Bedingung
    return True


def main():
    permutations = distinct_permutations([3, 3, 4, 4, 7, 7, 1, 1, 5, 5])
    total = ilen(side_effect(print, filter(check, permutations)))
    print("total =", total){
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Krischu
User
Beiträge: 95
Registriert: Dienstag 14. Januar 2014, 09:07

Danke für die stilistischen und idiomatischen Verbesserungen. Diese "komischen Sachen" rutschen mir da manchmal rein, wenn ich etwas analysieren oder verstehen will. total brauchte ich nur während des Entwickelns, um mir ein Bild von den Größen zu machen.

Code: Alles auswählen

 for a in b 
sollte man sich an den Spiegel stecken. Du hast ja recht :)

Was ich bräuchte, wären die Permutationen ausgedruckt, die den check() erfüllen. Insofern wäre eine kurze Erläuterung von ilen und side_effect noch hilfreich.
--
Grüße
Christoph
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Krischu: `more_itertools` ist doch dokumentiert. `side_effect()` ruft das erste Argument mit jedem Element aus dem iterierbaren zweiten Argument auf und liefert dann das Element unverändert weiter. Also hier werden alle Elemente die aus `filter()` kommen, mit `print()` ausgegeben. `ilen()` zählt einfach wie viele Elemente das iterierbare Objekt liefert. Also vom Effekt her ist ``ilen(iterable)`` äquivalent zu ``sum(1 for _ in iterable)``.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Krischu
User
Beiträge: 95
Registriert: Dienstag 14. Januar 2014, 09:07

__blackjack__ hat geschrieben: Montag 25. November 2024, 10:10 @Krischu: `more_itertools` ist doch dokumentiert. `side_effect()` ruft das erste Argument mit jedem Element aus dem iterierbaren zweiten Argument auf und liefert dann das Element unverändert weiter. Also hier werden alle Elemente die aus `filter()` kommen, mit `print()` ausgegeben. `ilen()` zählt einfach wie viele Elemente das iterierbare Objekt liefert. Also vom Effekt her ist ``ilen(iterable)`` äquivalent zu ``sum(1 for _ in iterable)``.

Code: Alles auswählen

side_effect(print, filter(check, permutations))   
 
Warum wird da nichts ausgegeben? Nur:

Code: Alles auswählen

<generator object side_effect at 0x7fb4d1b29c78>
--
Grüße
Christoph
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Krischu: Weil das das Ergebnis von `side_effect()` ist. Ein Generator. Erst das `ilen()` konsumiert die Elemente die der generiert, womit auch `filter()` überhaupt etwas macht, und `permutations` ebenfalls.

Code: Alles auswählen

In [95]: permutations
Out[95]: <generator object distinct_permutations.<locals>._full at 0x7f0d755f2f10>

In [96]: filter(check, permutations)
Out[96]: <filter at 0x7f0d737aa830>

In [97]: side_effect(print, filter(check, permutations))
Out[97]: <generator object side_effect at 0x7f0d704b3ed0>

In [98]: ilen(side_effect(print, filter(check, permutations)))
# *viele* Permutationen…
(7, 7, 5, 5, 4, 4, 1, 3, 3, 1)
(7, 7, 5, 5, 4, 4, 3, 1, 1, 3)
(7, 7, 5, 5, 4, 4, 3, 1, 3, 1)
(7, 7, 5, 5, 4, 4, 3, 3, 1, 1)
Out[98]: 113400
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Benutzeravatar
grubenfox
User
Beiträge: 548
Registriert: Freitag 2. Dezember 2022, 15:49

Wobei `side_effect()` noch ein paar zusätzliche Parameter hat, aber wenn es so genutzt wird, wie hier (eben ohne diese zusätzlichen Parameter), dann tut es doch auch einfach `map()` anstelle von side_effect, oder nicht?
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@grubenfox: In diesem speziellen Fall ja, weil `ilen()` egal ist ob es `None`-Objekte oder Tupel zählt. Aber ich fänd `map()` trotzdem schlechter an der Stelle weil man damit einen im Grunde nicht mehr wirklich brauchbaren Iterator über lauter `None`-Objekte erstellen würde. Und `map()` würde als Name auch verschleiern, dass der Grund das an der Stelle zu verwenden, der Nebeneffekt ist und nicht das man irgendwie transformierte Elemente haben möchte.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Benutzeravatar
grubenfox
User
Beiträge: 548
Registriert: Freitag 2. Dezember 2022, 15:49

Das stimmt wohl.. dafür kann es diesmal eben zu der Frage führen "warum nimmt er etwas aus einer externen Bibliothek, wenn es auch das sowieso schon vorhandene `map` auch tut?" ;) Aber es hat dazu geführt dass ich mir mal wieder die Doku von den more_itertools anschaute und wieder feststellte: "Hilfe, hier gibt es ja mehr Funktionen als ich mir merken kann...". Mal sehen, vielleicht kann man beim kommenden "Advent of Code" mal die eine und andere Funktion von dort gebrauchen...
[aber nun wird es doch hier etwas off-topic]
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@grubenfox: Die Frage ist leicht beantwortet: Weil ich es kann! 😜

Wobei es ein paar externe Bibliotheken gibt, die ich nur als ”halb”-extern sehe, weil die beispielsweise direkt in der Python-Dokumentation erwähnt werden. Die Dokumentation von `itertools` verweist beispielsweise auf das `more_itertools`-Modul. Und auf `attrs` würde ich auch nur sehr ungern verzichten.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Krischu
User
Beiträge: 95
Registriert: Dienstag 14. Januar 2014, 09:07

__blackjack__ hat geschrieben: Montag 25. November 2024, 13:20 @Krischu: Weil das das Ergebnis von `side_effect()` ist. Ein Generator. Erst das `ilen()` konsumiert die Elemente die der generiert, womit auch `filter()` überhaupt etwas macht, und `permutations` ebenfalls.

Code: Alles auswählen

In [95]: permutations

In [98]: ilen(side_effect(print, filter(check, permutations)))
# *viele* Permutationen…
(7, 7, 5, 5, 4, 4, 1, 3, 3, 1)
(7, 7, 5, 5, 4, 4, 3, 1, 1, 3)
(7, 7, 5, 5, 4, 4, 3, 1, 3, 1)
(7, 7, 5, 5, 4, 4, 3, 3, 1, 1)
Out[98]: 113400

Was muß ich machen, damit nur die gefilterten Permutationen ausgegeben werden? Ich brauche ilen() nicht.
--
Grüße
Christoph
Sirius3
User
Beiträge: 18078
Registriert: Sonntag 21. Oktober 2012, 17:20

Dann nimm doch einfach eine for-Schleife:

Code: Alles auswählen

from more_itertools import distinct_permutations


def check(a):
    # hier Code zum überprüfen eine Bedingung
    return True


def main():
    permutations = distinct_permutations([3, 3, 4, 4, 7, 7, 1, 1, 5, 5])
    for some_numbers in filter(check, permutations):
        print(some_numbers)

if __name__ == "__main__":
    main()
Krischu
User
Beiträge: 95
Registriert: Dienstag 14. Januar 2014, 09:07

Sirius3 hat geschrieben: Dienstag 26. November 2024, 09:52 Dann nimm doch einfach eine for-Schleife:

Code: Alles auswählen

from more_itertools import distinct_permutations


def check(a):
    # hier Code zum überprüfen eine Bedingung
    return True


def main():
    permutations = distinct_permutations([3, 3, 4, 4, 7, 7, 1, 1, 5, 5])
    for some_numbers in filter(check, permutations):
        print(some_numbers)

if __name__ == "__main__":
    main()
Danke. Jede Antwort wirft eine neue Frage auf:

Warum jetzt hier diese Konstrukt mit

Code: Alles auswählen

if __name__ == "__main__":
    main()
?
--
Grüße
Christoph
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Krischu: Damit man das importieren kann ohne das der Code in `main()` ausgeführt wird und damit man keine globalen Variablen hat.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Krischu
User
Beiträge: 95
Registriert: Dienstag 14. Januar 2014, 09:07

__blackjack__ hat geschrieben: Dienstag 26. November 2024, 11:06 @Krischu: Damit man das importieren kann ohne das der Code in `main()` ausgeführt wird und damit man keine globalen Variablen hat.
Ja, gut. Aber warum will ich mein eigenes kleines Programm importieren? Ich habe dieses main-Konstrukt öfters gesehen, aber bringt es hier jetzt was Essentielles außer, daß es die Diskussion am Laufen hält? Bitte, nichts für ungut :)
--
Grüße
Christoph
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Krischu: Zum Beispiel um die `check()`-Funktion mal mit ein paar Beispielfällen und/oder Randfällen auszuprobieren. Interaktiv in einer Python-Shell, oder automatisiert. Wenn der Code mit Beispielen dokumentiert ist/wird, um `doctest` darauf los zu lassen um zu prüfen ob das Beispiel korrekt ist. Um Werkzeuge verwenden zu können die Informationen dort heraus holen und dazu das Modul importieren um es zu untersuchen. Beispielsweise Dokumentationswerkzeuge. Damit andere Funktionen nicht aus versehen (oder gar absichtlich) globale Variablen verwenden. Damit die IDE da nicht alle globalen Variablen anmeckert, weil die Namen nicht der Schreibweise für Konstanten entspricht. Damit, wenn man solche Aufgaben mal auf mehrere Prozesse verteilen will, das `multiprocessing`-Modul auch auf allen Systemen wie erwartet funktioniert. Gibt bestimmt noch mehr Gründe.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Antworten