Frage zu Performance/Generatoren

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
Buchfink
User
Beiträge: 193
Registriert: Samstag 11. September 2021, 10:16

hi zusammen,

Hintergrund meiner Frage ist auch diesmal wieder (viewtopic.php?f=1&t=53315)

Ich verlagere es in einen eigenen Thread, da sich die "neue" von mir erdachte Aufgabenstellung ein wenig von dem unterscheidet, was dort mal von mir beschrieben wurde.

Beim Lernen, wie das NLP-Paket "spaCy" und die darin enthaltenen Sematik-Vergleichsmöglichkeit funktioniert, kam mir die Idee:
Würde man herausfinden können, ob es auch ähnliche Sprichwörter gibt?

Spoiler (ja, gibt es und funktioniert tatsächlich ganz gut)

Also die Frage ist schon beantwortet - allein der Weg gefällt mir nicht, denn er scheint mir recht umständlich /unperformant zu sein. Denn es wäre z.B. praktisch an der "Ähnlichkeitsschwelle" herumzujustieren und zu gucken, ab wo man ein wirklich gutes Ergebnis erhält. Leider dauert jeder Durchlauf mit ca 1000 Sprüchen mehr als eine halbe Stunde.

Code: Alles auswählen

import logging
from pathlib import Path
import spacy

nlp = spacy.load("de_core_news_lg")
logger = logging.getLogger(__name__)

BASE_PATH = Path("Daten", "WortspielGenerator")
IDENTITY = 1.0
THRESHOLD_SIMILAR = 0.86


def initialize_logging():
    logs_path = BASE_PATH / "logs"
    logs_path.mkdir(parents=True, exist_ok=True)
    log_file_path = logs_path / "Sprueche_ausgemustert.txt"
    logging.basicConfig(filename=str(log_file_path), level=logging.ERROR)


def read_sayings(filename):
    #
    # TODO Verbesserung mittels wiki-api - Texte direkt aus Wikipedia
    #   "Sprichwörter" auslesen?
    #
    # Tutorials:
    #  - https://wdqs-tutorial.toolforge.org/index.php/simple-queries/the-simplest-query/basic-sparql-query/
    #  - https://docs.python.org/3/howto/logging.html#logging-basic-tutorial
    #  - https://course.spacy.io/en/chapter1
    #
    with open(filename, "r", encoding="UTF-8") as file:
        for line_number, line in enumerate(file, 1):
            if line.startswith('"'):
                saying, seperator, _ = line[1:].partition('"')
                if seperator:
                    yield saying
                else:
                    logging.error(
                        "Ende von Spruch in Zeile %d nicht gefunden: %r",
                        line_number,
                        line,
                    )
            else:
                line = line.rstrip()
                if not (len(line) == 1 and line.isalpha()):
                    logging.error(
                        "Unerwartete(s) Zeichen in Zeile %d: %r",
                        line_number,
                        line,
                    )


def compare_sayings(filename):
    compared_sayings = {}
    for saying_a in read_sayings(filename):
        for saying_b in read_sayings(filename):
            if saying_b + saying_a not in compared_sayings:
                doc_a = nlp(saying_a)
                doc_b = nlp(saying_b)
                similar = doc_a.similarity(doc_b)
                compared_sayings[saying_a+saying_b] = (saying_a, saying_b, similar)
    return compared_sayings


def find_similar_sayings(compared_sayings):
    for key, (saying_a, saying_b, similar) in list(compared_sayings.items()):
        if similar == IDENTITY or similar < THRESHOLD_SIMILAR:
            compared_sayings.pop(key)
    return compared_sayings


def show_sayings(sayings):
    for element, (saying_a, saying_b, similar) in sayings.items():
        print(saying_a)
        print(saying_b)
        print(similar)
        print('----------------------------')


def main():
    initialize_logging()
    sayings_file_path = BASE_PATH / "Sprueche_A.txt"
    compared = compare_sayings(sayings_file_path)
    similar = find_similar_sayings(compared)
    show_sayings(similar)


if __name__ == "__main__":
    main()
Insbesondere "compare_sayings" ist sehr langsam.
Ich hab mich daher auf die Suche gemacht und mal geschaut, wie man ggf. die Performance noch verbessern kann:

Die Performance der eigentlichen Vergleichsfunktion kann ich erst mal nicht weiter beeinflussen.

Folgendes würde mir einfallen:
1) Jeden Spruch mit jedem anderen zu vergleichen, macht keinen Sinn. Es reicht nur eine Richtung zu vergleichen, da es ja symmetrisch ist. f(A,B) = f(B,A)
Dies ist im obigen Code schon berücksichtigt
2) Einen Spruch mit sich selbst zu vergleichen, ist auch Quatsch, da dies ja immer zu Identität führt. (Dies ist in compare_sayings nicht berücksichtigt und wird nur umständlich später wieder "herausgeporkelt" :-( )

Ich habe das Problem mal versucht isoliert zu betrachten und habe auch mal die Performance gemessen:

Code: Alles auswählen

texts = ['Adel', 'Sargnagel', 'Baum', 'Raum', 'Berg', 'Zwerg', 'Esel', 'Sessel', 'Flügel', 'Kleiderbügel', 'Geld', 'Held']

def compare(text_a, text_b):
    # _eigentlich_ kommt hier ein zeitlich teurer Vergleich im Hinblick auf die Semantik
    # aus Gründen der Lesbarkeit "banalisiert":
    return text_a == text_b

def compare_texts1():
    compared_texts = {}
    for text_a in texts:
        for text_b in texts:
            # wg. Symmetrie reicht der Vergleich in eine Richtung
            if text_b + text_a not in compared_texts:
                compared_texts[text_a+text_b] = (text_a, text_b, compare(text_a, text_b))
    return compared_texts


def compare_texts2():
    compared_texts = {}
    for i in range(len(texts)):
        for j in range(i, len(texts)):
            text_a = texts[i]
            text_b = texts[j]
            compared_texts[text_a+text_b] = (text_a, text_b, compare(text_a, text_b))
    return compared_texts


def compare_texts3():
    compared_texts = []
    for i in range(len(texts)):
        for j in range(i, len(texts)):
            text_a = texts[i]
            text_b = texts[j]
            compared_texts.append((text_a, text_b, compare(text_a, text_b)))
    return compared_texts
    
 def compare_texts4():
    compared_texts = []
    for i in range(len(texts)):
        for j in range(i + 1, len(texts)):
            text_a = texts[i]
            text_b = texts[j]
            compared_texts.append((text_a, text_b, compare(text_a, text_b)))
    return compared_texts
    
%timeit compare_texts1()
%timeit compare_texts2()
%timeit compare_texts3()
%timeit compare_texts4()
führt zu folgendem Ergebnis: 4 gewinnt :)

Code: Alles auswählen

46.9 µs ± 813 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
36.8 µs ± 5.37 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
32.8 µs ± 2.51 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
27.5 µs ± 2.67 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Und ab hier bin ich verwirrt:
"read_sayings(filename)" ist ja ein Generator - wenn ich das richtig verstehe.
D.h. ich habe keinen Index, wie oben im Experimental-Code.
Ich hatte dann die Idee "compare_sayings" selbst in einen Generator umzubauen, aber wie erkenne ich, welche Pärchen ich schon verglichen habe?

Ich fürchte, dass hier gerade voll auf der Leitung stehe.... :-(

Ich hatte auch schon überlegt, die Werte als CSV zu persistieren, so dass man leichter den Threshold ändern könnte, um zu sehen, wie gut ein höherer Wert funktioniert, indem man einmal die Vergleichsmatrix berechnet und diese dann immer wieder lädt, falls sie noch nicht vorhanden ist. (Was meint ihr dazu?)

Nun wie dem auch sei, ich freue mich, ob ihr vielleicht noch Ideen habt.

(Wenn mein Text zu lang ist, dann bitte auch gerne sagen/schreiben.)

Edit: Link korrigiert
Benutzeravatar
__blackjack__
User
Beiträge: 14020
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Buchfink: Ich würde da ja auf Lesbarkeit setzen und damit sind IMHO die Indexzugriffsvarianten alle schon mal raus. Wenn man sich um so ein bisschen Laufzeit Gedanken macht, ist Python sowieso die falsche Sprache.

Was beim original `compare_sayings()` auffällt, ist das in der inneren Schleife die Datei immer wieder neu gelesen/geparst wird. *Das* dürfte schon mal *deutlich* mehr Laufzeit kosten als ein Unterschied zwischen Generator und manuellem Indexzugriff.

Dann kann man die Möglichkeiten Paare zu bilden ganz einfach mit `itertools.combinations()` erschlagen und muss sich da nicht selbst einen Kopf machen.

`compared_sayings` ist ein bisschen redundant aufgebaut. Die beiden Sprichwörter sind sowohl Schlüssel als auch im Wert — dann kann man sich das sparen die in den Wert zu stecken.

Und damit wird die Schleife letztlich so einfach, dass man eine „dict comprehension“ daraus machen kann. Aaaaber eigentlich braucht man das Wörterbuch an der Stelle auch gar nicht mehr, denn Doubletten rausfiltern ist durch `combinations()` unnötig.

`find_similar_sayings()` ist unschön. Statt etwas aus Datenstrukturen zu entfernen ist es in der Regel besser, weil einfacher, einfach eine neue Datenstruktur zu erstellen, die nur die gewünschten Werte enthält. Eine Kopie als Liste musstest Du da ja sowieso schon anlegen. Allerdings kann man, wenn man einen Generator übergeben bekommt, den auch einfach als gefilterten Generator zurückgeben.

Ungetestet:

Code: Alles auswählen

@attrs(frozen=True)
class ComparisonResult:
    saying_a = attrib()
    saying_b = attrib()
    similarity = attrib()


def compare_sayings(filename):
    return (
        ComparisonResult(
            saying_a, saying_b, nlp(saying_a).similarity(nlp(saying_b))
        )
        for saying_a, saying_b in combinations(read_sayings(filename), 2)
    )


def find_similar_sayings(compared_sayings):
    return filter(
        lambda pair: pair.similarity >= SIMILARITY_THRESHOLD, compared_sayings
    )
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
narpfel
User
Beiträge: 690
Registriert: Freitag 20. Oktober 2017, 16:10

Was eventuell auch viel (unnötige) Zeit frisst, ist das mehrfache Aufrufen von `nlp` mit den Sprichwörtern. Ich kenne mich mit NLP gar nicht aus, aber wenn `spaCy` da was kompliziertes macht, könnte das hier auch noch mal schneller sein:

Code: Alles auswählen

def compare_sayings(filename):
    parsed_sayings = ((saying, nlp(saying)) for saying in read_sayings(filename))
    return (
        ComparisonResult(saying_a, saying_b, parsed_a.similarity(parsed_b))
        for (saying_a, parsed_a), (saying_b, parsed_b) in combinations(parsed_sayings, 2)
    )
Buchfink
User
Beiträge: 193
Registriert: Samstag 11. September 2021, 10:16

@__blackjack__

lieben Dank für Deine Antwort!
Ich würde da ja auf Lesbarkeit setzen und damit sind IMHO die Indexzugriffsvarianten alle schon mal raus.
ja, das hatte mir an diesen Variante auch nicht gefallen. Und den Code soweit umbauen, dass ein Index-Zugriff möglich gewesen wäre, kam mir falsch vor, da sich das so "unpythonisch" angefühlt hätte. Daher die isolierte Betrachtung, um zu sehen, ob das überhaupt was bringt und wieviel.
Ich muss in meinem Hirn mal FreeAndNil(FDelphiDenke) aufrufen... vielleicht wird's dann besser mit meinen Lösungsideen. ;-)
Was beim original `compare_sayings()` auffällt, ist das in der inneren Schleife die Datei immer wieder neu gelesen/geparst wird. *Das* dürfte schon mal *deutlich* mehr Laufzeit kosten als ein Unterschied zwischen Generator und manuellem Indexzugriff.
hm ja, guter Punkt. Ich tue mich leider :-( noch ein bisschen schwer mit den Generatoren. Wann genau bringen sie Vorteile? Und welche Vorteile (mal abgesehen von der Lesbarkeit)?
Hier muss ich mal überlegen, wie man den Dateizugriff eliminieren könnte. Dateiinhalt in eine Datenstruktur ziehen, vielleicht? Oder meinst Du was anders?
Dann kann man die Möglichkeiten Paare zu bilden ganz einfach mit `itertools.combinations()` erschlagen und muss sich da nicht selbst einen Kopf machen.
sehr schön, dass es diese Möglichkeit gibt! (Leider habe ich das über die Google Suche nicht gefunden :-( )
`compared_sayings` ist ein bisschen redundant aufgebaut. Die beiden Sprichwörter sind sowohl Schlüssel als auch im Wert — dann kann man sich das sparen die in den Wert zu stecken.
ja, korrekt. Mein Gedanke war, ich mir das spätere "Auseinanderdröseln" des Schlüssels "ersparen" wollte. Die Lösung mit dem Dictionary hatte mir aber auch nicht besonders gut gefallen.
`find_similar_sayings()` ist unschön. Statt etwas aus Datenstrukturen zu entfernen ist es in der Regel besser, weil einfacher, einfach eine neue Datenstruktur zu erstellen, die nur die gewünschten Werte enthält. Eine Kopie als Liste musstest Du da ja sowieso schon anlegen. Allerdings kann man, wenn man einen Generator übergeben bekommt, den auch einfach als gefilterten Generator zurückgeben.
ja, das stimmt wohl. Das hätte ich nochmal über meinen Code lesen sollen. In meinem allerersten Wurf war das noch anders herum, da das ja der "natürlichere" Weg ist. Durch verschiedene Umbauten ist das irgendwann "abhanden gekommen".
Tja nun :) Intension war die Daten von der Ausgabe zu trennen.

zum Code
Du hattest ja geschrieben "ungetestet".

Ich habe nur zusätzlich noch folgendes geändert:

Code: Alles auswählen

import logging
import spacy
from pathlib import Path
from attr import attrs, attrib
from itertools import combinations
sowie

Code: Alles auswählen

def show_sayings(similarities):
    for similarity in similarities:
        print(similarity.saying_a)
        print(similarity.saying_b)
        print(similarity.similarity)
        print('----------------------------')
Damit funktioniert es. :)
Das Performance-Problem ist allerdings wohl wg. des Dateizugriffs noch enthalten. Hier muss ich morgen nochmal drüber nachdenken.

Dankeschön für den Code :)
Buchfink
User
Beiträge: 193
Registriert: Samstag 11. September 2021, 10:16

@narpfel
vielen Dank! :)

"Gefühlt" ist es mit Deinem Vorschlag schneller.

Allerdings habe ich jetzt nicht gemessen. Das will ich morgen mal machen.

Ich muss auch gestehen, dass ich morgen nochmal genauer lesen muss, denn ich glaube, dass ich den Code noch nicht vollständig verstanden habe. Und das wäre mittelfristig ja nicht gut.

LG
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Da es mich interessiert hat, habe ich es mal selbst versucht und dabei die Vorschläge von __blackjack__ und narpfel berücksichtigt.
Besonders der Vorschlag von narpfel hat so eine enorme Beschleunigung gebracht, dass ich schon an der Richtigkeit gezweifelt hatte.

Daher habe ich auch "get_similar_sayings_slow" zum Vergleich behalten.
Es werden aber wirklich in beiden Fällen die gleiche Anzahl von Kombinationen ausgewertet.
Mit "get_similar_sayings_fast" dauert es insgesamt gefühlte 10 Sekunden.

Die Sprichwörter werden direkt aus Wikiquote geholt. Aktuell werden 903 gefunden.

Man wundert sich, dass spacy Ähnlichkeiten findet wo man eigentlich keine erwartet. Das liegt daran, dass spacy auch Worte berücksichtigt, die nicht zum Sinn des Satzes beitragen. Etwas googeln klärt dann, dass man "stop-words" filtern könnte.

Das Ergebnis ist besser aber immer noch nicht befriedigend wie man an den drei Beispielen sieht:

Nr. 69: Keine Ahnung was da passiert ist ???
Nr. 94: Schlechtes Beispiel (Wahrscheinlich sind beim Filern zu viele Worte rausgefallen)
Nr. 125: Gutes Beispiel

Code: Alles auswählen

import re
import spacy
import requests
from bs4 import BeautifulSoup
from itertools import combinations

URL = "https://de.wikiquote.org/wiki/Deutsche_Sprichw%C3%B6rter#A"
THRESHOLD_SIMILAR = 0.85

nlp = spacy.load("de_core_news_lg")


def request_page(url):
    response = requests.get(url)
    return response.content


def get_list_elements(url):
    page = request_page(url)
    soup = BeautifulSoup(page, "html.parser")
    raw_content = soup.find(id="mw-content-text")
    return raw_content.find_all("li")


def extract_sayings(url):
    pattern = re.compile(r'"(.*?)"')
    for text_block in get_list_elements(url):
        match = pattern.match(text_block.text)
        if match:
            yield match.groups()[0]


def make_filtered_nlp(sentence):
    return nlp(" ".join(str(word) for word in nlp(sentence) if not word.is_stop and not word.is_punct))


def get_similar_sayings_fast(url, minimum_similarity):
    parsed_sayings = ((saying, make_filtered_nlp(saying)) for saying in extract_sayings(url))
    for (this, this_doc), (other, other_doc) in combinations(parsed_sayings, 2):
        similarity = this_doc.similarity(other_doc)
        if similarity > minimum_similarity:
            yield this, other, similarity


def get_similar_sayings_slow(url, minimum_similarity):
    for this, other in combinations(extract_sayings(url), 2):
        similarity = make_filtered_nlp(this).similarity(make_filtered_nlp(other))
        if similarity >= minimum_similarity:
            yield this, other, similarity


def main():
    for num, (this, other, similarity) in enumerate(get_similar_sayings_fast(URL, THRESHOLD_SIMILAR), 1):
        print(f"{num:4d}: Similarity: {similarity:0.2f}")
        print(this)
        print(other)
        print("-" * 80)


"""
  69: Similarity: 1.00
Ein Unglück kommt selten allein.
Ein Unglück kommt selten allein.
--------------------------------------------------------------------------------
  94: Similarity: 1.00
Es hat nicht sollen sein.
Weniger ist mehr!
--------------------------------------------------------------------------------
 125: Similarity: 0.93
In der Nacht sind alle Katzen grau.
Nachts sind alle Katzen grau.
"""

if __name__ == "__main__":
    main()
Ich verwende hier Generatoren weil man sie so schön verketten kann, nicht wegen der Geschwindigkeit.
Buchfink
User
Beiträge: 193
Registriert: Samstag 11. September 2021, 10:16

@roger_b

Dankeschön!
Der Weg über BeautifulSoup kam mir auch schon in den Sinn.
Da warst Du jetzt schneller als ich :)

Es gibt auch noch die Möglichkeit, über eine API direkt Wikipedia anzusteuern. (Leider gilt das aber wohl nicht für Wikiquote. Zumindest bin ich vor 6 Wochen nicht fündig geworden. An Bud-Spencer-Filmtitel kommt man aber damit problemlos dran :))
Bei BeautifulSoup war ich bis dato zurückhaltend, weil ich da ein wenig Bedenken hatte, was und wie man das genau darf. Ich kenne es bislang nur aus einem Tutorial, was ich mal im Sommer gemacht hatte.

Mein Gedanke war, aus verschiedenen (Text)Quellen Daten anzuziehen (auch Datei-basiert), um dann sprachlich damit "herumzujonglieren". Natürlich :) mit dem Ziel, bisschen was über verschiedene Formate und deren Import mittels Python zu lernen. Bzw. darüber wie man bisschen größere Projekte in Python strukturieren würde.

Deswegen interessiert mich weiterhin der "Weg" über das Einlesen der Datei. :)

Das Beispiel mit dem Ergebnis 1.0 kam mir etwas merkwürdig vor. Ich habe das mal direkt angeschaut und komme auf ein anderes Ergebnis:

Code: Alles auswählen

print("Sprüche")
doc_a = nlp("Es hat nicht sollen sein.")
doc_b = nlp("Weniger ist mehr!")
print(f"{doc_a}, {doc_b}: {doc_a.similarity(doc_b)}")

--->
Sprüche
Es hat nicht sollen sein., Weniger ist mehr!: 0.5367577129248948
Das passt schon besser, denke ich. Ich schau mal, ob ich herausfinde, woran es liegt.

Wenn man der Pipeline (ich glaube so heißt es) unbekannte Worte übergibt, kommt es zu einer Warnung

Code: Alles auswählen

woerter = [
    ("Hafen", "Hafen"),
    ("Hafen", "Hafer"),
    ("Hafen", "Hafel")
]

print("Ähnlichkeiten Wörtern")
for word_a, word_b in woerter:
    doc_a = nlp(word_a)
    doc_b = nlp(word_b)
    print(f"{doc_a}, {doc_b}: {doc_a.similarity(doc_b)}")

---> 
Ähnlichkeiten Wörtern
Hafen, Hafen: 1.0
Hafen, Hafer: 0.2566759850874994
C:/Users/Buchfink/PycharmProjects/TKocher/beispiel_spacy_similary.py:63: UserWarning: [W008] Evaluating Doc.similarity based on empty vectors.
  print(f"{doc_a}, {doc_b}: {doc_a.similarity(doc_b)}")
Hafen, Hafel: 0.0
Man wundert sich, dass spacy Ähnlichkeiten findet, wo man eigentlich keine erwartet. Das liegt daran, dass spacy auch Worte berücksichtigt, die nicht zum Sinn des Satzes beitragen. Etwas googeln klärt dann, dass man "stop-words" filtern könnte.
Ja, das mit den Stop-words wird auch im Tutorial erwähnt. https://course.spacy.io/en/chapter1
Den Eindruck, dass es spacy arg oft _völlig_ danebenhaut hatte ich allerdings nicht.

LG
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Das Beispiel mit dem Ergebnis 1.0 kam mir etwas merkwürdig vor. Ich habe das mal direkt angeschaut und komme auf ein anderes Ergebnis:
Ja, da wurden zu viele Worte ausgefiltert. In meiner Version bleibt verborgen, dass in einigen Fällen so viel gefiltert wurde, dass die Sätze identisch werden.
Man kann das sicher noch optimieren. Dafür kenne ich spacy aber nicht gut genug.

Bzgl. BeautifulSoup würde ich es normalerweise so machen, dass ich die Daten nur einmal hole und dann eine lokale Kopie verwende. Im Forum finde ich es aber immer Schade, wenn jemand eigene Dateien verwendet, die anderen nicht zur Verfügung stehen.
narpfel
User
Beiträge: 690
Registriert: Freitag 20. Oktober 2017, 16:10

rogerb hat geschrieben: Donnerstag 30. Dezember 2021, 16:40 Im Forum finde ich es aber immer Schade, wenn jemand eigene Dateien verwendet, die anderen nicht zur Verfügung stehen.
Das hat mich auch davon abgehalten, das zu benchmarken anstatt nur einen (un)educated guess zu machen. :-)
Buchfink
User
Beiträge: 193
Registriert: Samstag 11. September 2021, 10:16

@narpfel und @roger_b

ja, den Einwand kann ich absolut nachvollziehen.
Im Hinblick auf die Reproduzierbarkeit ist das ein Problem. Es bedeutet vor allem höheren Zeitaufwand für diejenigen, die gern helfen (möchten). Bzw. es ist natürlich "abschreckend" mir diesbezüglich zu helfen.
Ich erinnere mich dunkel, dass ich das auch in einem anderen Beitrag selbst schon mal eingewandt und gefragt hatte, wie ich das verbessern könnte. (Leider finde ich die Stelle nicht mehr)

Das tut mir auch ehrlich leid, wenn das jetzt irgendwie so rübergekommen ist, als würde ich auf "das Einlesen per Datei" bestehen. Ich möchte keinesfalls unnötig Aufwand generieren und dafür entschuldige ich mich. Denn das war so gar nicht gedacht.

Bitte schreibt mir gerne, wie ich das bei meinen Beiträgen verbessern kann.

Um das Problem der teureren Reproduzierbarkeit etwas zu entschärfen, versuche ich möglichst immer das Problem zu abstrahieren. Aber wie man am Beispiel oben sieht, greift das manchmal dann eben wieder zu kurz. Und mein Eindruck ist, dass hier Entwickler schreiben, die gern den Gesamtkontext kennen möchten (was ich im Übrigen vollkommen nachvollziehen kann)

Das mit der Datei interessiert mich eigentlich nur deshalb, weil ich in der Praxis meistens Dateien habe und da würde ich vermutlich irgendwann vor dem gleichen Problem stehen.
Mir ist in der Regel aber auch schon geholfen, mit einem Tipp nach was ich suchen kann. Und wenn jemand einfach was ungetestet aus dem Ärmel schüttet, komme ich auch damit weiter. :)

Das Problem der Reproduzierbarkeit kenne ich auch aus dem beruflichen Kontext, wenn eine Bug-Meldung kommt a´la "Guck mal auf dem Dialog da, da ist was komisch".... "ähm, ja, kann man da lachen oder warum ist es komisch?" :)
Ich kann vollkommen verstehen, dass sowas ärgerlich ist.

Ich habe auch schon überlegt, ob ich mein Zeug einfach bei GitHub hochlade. (Aber da kenne ich mich leider noch gar nicht aus)

Am Rande:
Wie kann ich denn hier im Forum komplette Dateien hochladen? (Ich vermute nur in Code-Tags?)

Liebe Grüße und Dankeschön für Eure hilfreichen Beiträge!
Buchfink
User
Beiträge: 193
Registriert: Samstag 11. September 2021, 10:16

Ergänzung: ich freue mich über jede Form der Hilfe - auch über seelisch-moralischen Beistand :) Ehrlich! :-)
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Also, das war keine Kritik, von mir sondern nur eine allgemeine Bemerkung. Manchmal probiere ich gerne etwas aus. Wenn das nicht geht ist es nur Schade aber nicht weiter Schlimm.
Code rein durch Lesen zu verstehen ist ja auch eine gute Übung.

Andererseits bekommt man sicher bessere Unterstützung wenn der Code von anderen ausprobiert und analysiert werden kann.
Hier im Forum kann man keine Dateien hochladen. Die bessere Lösung ist es eine kleine lauffähige Minimalversion zur Verfügung zu stellen. So steht es, glaube ich. auch irgendwo in den FAQs. Aber befolgen tuen das die wenigsten. Es erfordert natürlich auch eine gewisse Übung.
Buchfink
User
Beiträge: 193
Registriert: Samstag 11. September 2021, 10:16

@roger_b
Ich habe das als Feedback aufgefasst - im Sinne von "da könntest Du was verbessern" :) - Also gar nicht negativ. :) Und das ist absolut in meinem Sinne, denn ich möchte hier keinesfalls unnötige Aufwände generieren.

(Das ist übrigens der Eintrag den ich oben meinte: viewtopic.php?f=1&t=53315&start=15, vgl. Sonntag 31. Oktober 2021, 18:05)
ich hatte mich dann, weil zumindest niemand Einwände hatte, dazu entschlossen, den Code mal zu posten.

Ich hatte auch etwas Bedenken, da ich mit spaCy ja auch eine eher selten genutzte Lib anziehe, die ggf. teilweise dann noch nachinstalliert werden muss, um das Problem zu nachzuvollziehen. Das ist leider auch Aufwand.
Die bessere Lösung ist es eine kleine lauffähige Minimalversion zur Verfügung zu stellen.
ja, das sehe ich auch so. Und ich versuche das auch, aber es ist manchmal gar nicht so leicht, die _richtigen_ Fragen zu stellen.
Manchmal abstrahiere ich ggf. das falsche Problem. Bzw. ich hab z.B. öfter noch die Denkweise von Delphi im Kopf und da hab' ich teilweise das Gefühl, dass es besser ist, den gesamten Code zu posten, um etwas mehr Kontext zu liefern, weil es unter Python oft _ganz_ andere Ansätze gibt.
Teilweise wäre es auch wiederum besser, das thematisch auf verschiedene Threads aufzuteilen ("Code-Review" + "Frage zu Thema ABC"). Ich bin da oft auch ein bisschen unentschlossen, und weiß leider nicht immer richtig einzuschätzen, wie es am besten wäre.

Vielleicht splitte ich meine Einträge künftig in "Kontext" und "Konkretes Problem". Würde das helfen?

Wie dem auch sei: ich bin für Verbesserungsvorschläge offen. :)
Buchfink
User
Beiträge: 193
Registriert: Samstag 11. September 2021, 10:16

@roger_b
Ja, da wurden zu viele Worte ausgefiltert. In meiner Version bleibt verborgen, dass in einigen Fällen so viel gefiltert wurde, dass die Sätze identisch werden.
Man kann das sicher noch optimieren. Dafür kenne ich spacy aber nicht gut genug.
Hab's nun auch im Code gesehen, wo das passiert. :)

Ich habe ein bisschen gebraucht, bis ich in der Lage war, das vollständig nachzuvollziehen. Also ich kann's jetzt lesen und debuggen. Selbst schreiben könnte ich das in dieser kompakten Form (noch) nicht.
Antworten