diff --git a/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S2.md b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S2.md new file mode 100644 index 0000000..2ca5b99 --- /dev/null +++ b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S2.md @@ -0,0 +1,178 @@ +# Recherche zu benötigten Techniken (Tim Ronneburg) +In diesem Kapitel werden die Prämissen behandelt, welche zu Beginn des Projektes festgelegt und anhand derer eine Auswahl an benötigten Techniken getroffen wurde. + +Die im Folgenden genannten Werkzeuge und Technologien werden an den entsprechenden Stellen später detaillierter behandelt. Dieses Kapitel dient daher als Zusammenfassung der Anforderungen mit nachfolgender Auswahl der Technologien. Diese Auswahl wird im anschließenden Kapitel 3, das die Zwischenberichte des Projekts umfasst, eingehender und ausführlicher behandelt. + +Bei der Auswahl der Technologien für das Projekt werden verschiedene Gesichtspunkte berücksichtigt. Insbesondere stehen folgende Fragen im Fokus: + +- Welches Tool zur Visualisierung soll verwendet werden? +- Auf welche Weise erfolgt die Berechnung und Visualisierung von Graphen und Netzwerken? +- Wie wird die Bereitstellung der Webseite durchgeführt? +- Welche Datenbanken kommen für die Sammlung und Bereitstellung der Informationen zum Einsatz? +- Wie wird die Stimmung der Nachrichten zu einer Firma ausgewertet? + +Auf die Fragestellung wie in der Projektgruppe zusammengearbeitet wird und welche Werkzeuge dafür zum tragen kommen - Stichwort: Git - wurde bereits im vorherigen Kapitel behandelt und wird hier nicht weiter betrachtet. + +Für die aufgelisteten Fragestellungen setzt sich jeweils ein Gruppenmitglied intensiv mit der Thematik auseinander und stellt eine Auswahl an möglichen Technologien der Projektgruppe vor. Nach mehreren Iterationen der Evaluation wird eine Auswahl an Werkzeugen getroffen. + +Generell werden für sämtliche Aspekte die allgemeinen Leitlinien berücksichtigt. Die eingesetzten Werkzeuge und Technologien sollen Open Source sein, also frei verfügbar und ohne zusätzliche Kosten. Die Programmiersprache basiert auf Python, da sie von allen Gruppenmitgliedern beherrscht wird und die Verwendung mehrerer Sprachen das Projekt unnötig komplex machen würde. Die gewählten Technologien integrieren sich nahtlos in die Arbeitsweise mit DevOps und Git und sind durch automatisierte Tests überprüfbar. Dadurch wird eine einheitliche Arbeitsweise gewährleistet, und Engpässe durch isolierte Anwendungen werden vermieden. Schließlich legen wir Wert darauf, dass alle zu berücksichtigenden Werkzeuge einfach bedienbar sind, um einen reibungslosen Einstieg in die Technologie zu ermöglichen und die Beteiligung aller Teammitglieder zu erleichtern. + +## Technische Anforderungen +Neben den allgemein geltenden Anforderungen wird in diesem Unterkapitel auf die technischen Anforderungen je Kategorie eingegangen. Die Kategorien wurden aus den oben ganannten Fragestellungen abgeleitet und entsprechen den Arbeitsbereichen der einzelnen Gruppenmitglieder sowie die Kernelemente des Projektes. Die Gruppen/Kategorien lauten: +- DevOps +- Text Mining +- Datenspeicherung +- Sentimentanalyse +- Verflechtungsanalyse +- Visualisierung + +Diese Einteilung findet sich im Verlauf der Dokumentation immer wieder. Zusätzlich kommt in diesem Teil noch das Unterkapitel "Provisionierung" hinzu indem auf die Vorgaben für die Bereitstellung der Anwendung für die Nutzer eingegangen wurde. +Im Folgenden wird kurz auf die Kategorien eingegangen und die speziellen Anforderungen für den jeweiligen Bereich dargelegt, welche es bei der Rechereche zu betrachten galt. + +### DevOps +Dieser Abschnitt befasst sich mit der Versionskontrolle des Quellcodes, automatisierten Tests und der automatisierten Bereitstellung der Anwendung auf einem Server. Im Kapitel 3.1 wird dieses Thema theoretisch und in Kapitel 4.2 praktisch behandelt, weshalb sich dieser Abschnitt auf die Anforderungen auf höchster Ebene konzentriert. + +Bei der Implementierung von DevOps ist es entscheidend herauszufinden, welche Versionskontrollsoftware genutzt werden soll, wie DevOps darin integriert werden kann und für welche Aspekte des Projekts DevOps sinnvoll eingesetzt wird. + +Die Versionskontrollsoftware muss für alle Beteiligten leicht zugänglich sein und keine zusätzlichen Konten erfordern. Sie sollte die Zusammenarbeit im Team ermöglichen, indem mehrere Personen an denselben Dateien arbeiten können, die dann von der Versionskontrollsoftware zusammengeführt werden. + +DevOps muss in dieser Software implementiert werden können, um eigene Pipelines zu erstellen, die die Anwendung testen und bereitstellen. + +Unter Berücksichtigung der allgemeinen Vorgaben lauten die Prämissen für die Recherche der DevOps-Technologien wie folgt: + +- Auswahl einer Versionskontrollsoftware, die eine kollaborative Arbeit des Teams am Quellcode ermöglicht. +- Die Technologie sollte das Erstellen eigener Pipelines unterstützen. +- Die Technologie sollte kostenlos und frei verfügbar sein. +- Die Technologie sollte mit Python kompatibel sein. + +### Text Mining +Die Text Mining-Kategorie konzentriert sich auf das Sammeln von relevanten Unternehmensinformationen für das Projekt. Diese Daten werden im Abschnitt zur Datenspeicherung gesichert und der Projektgruppe zur Verfügung gestellt. Ähnlich wie im vorherigen Kapitel wurde dieses Thema in den Kapiteln 3.2 sowie 4.3 bis 4.4 eingehender behandelt. + +In diesem Bereich ist es erforderlich, ein Werkzeug zu finden, das APIs aus dem Internet abfragt und die Daten entweder sichert oder transformiert. Dies betrifft insbesondere Beziehungsdaten aus dem Unternehmensregister für die Netzwerkanalyse, Stammdaten, verschiedene Nachrichten-APIs für die Stimmungsanalyse bezogen auf jedes einzelne Unternehmen sowie Finanzdaten aus dem Bundesanzeiger. + +Besonders beim Extrahieren von Daten aus dem Bundesanzeiger besteht die Herausforderung darin, die Informationen in ein einheitliches Format zu überführen. Die Schwierigkeit ergibt sich aus der Tatsache, dass die Informationen als Jahresberichte vorliegen, die von jedem Unternehmen in eigener Form erstellt werden. Das Tool muss daher in der Lage sein, die Berichte zu analysieren und die gesuchten Daten zu extrahieren, auch wenn sie in Tabellen oder Fließtexten vorliegen. + +Zusammengefasst sind die Kriterien für die Technologie: + +- Abfrage und Auswertung des Unternehmensregisters und von Nachrichten-APIs +- Aufbereitung der Daten in ein einheitliches Format +- Sicherung der Daten in einer Datenbank gemäß dem vorgegebenen Datenbankschema +- Die Technologie sollte kostenlos und frei verfügbar sein. +- Die Technologie sollte mit Python kompatibel sein. + +### Datenspeicherung +Für die Datenspeicherung ist die Entwicklung eines Schemas erforderlich, das nicht nur die durch Text Mining gewonnenen Daten sichert, sondern auch während der Analyse generierte Daten speichert. Zudem müssen die Daten für die Analyse und die Programm-Aufbereitung abrufbar sein. Dieser Aspekt wird im Kapitel 3.3 genauer behandelt. + +Es wird also nach einer oder mehreren Datenbanken gesucht, die folgende Anforderungen abdecken: + +- Auswahl einer Datenbank als Data Lake für das Text Mining. +- Auswahl einer Datenbank für die transformierten Daten aus dem Data Lake. +- Abwägung zwischen NoSQL- und SQL-Datenbanken. +- Die Technologie sollte kostenlos und frei verfügbar sein. +- Die Technologie sollte mit Python kompatibel sein + +### Sentimentanalyse + +Die Sentimentanalyse beinhaltet die Bewertung von Nachrichten im Hinblick auf die darin erwähnten Unternehmen. Es wird untersucht, ob die betreffenden Unternehmen positiv oder negativ dargestellt werden. Diese Information wird, bei ausreichender Datenlage, im Transparenzregister als Stimmung angegeben. + +Da eine manuelle Analyse aufgrund der großen Menge täglicher Nachrichten nicht durchführbar ist, wird nach einer Technologie gesucht, die automatisch die Daten analysiert, die Unternehmensnamen identifiziert, die Stimmung des Textes gegenüber dem Unternehmen bewertet und diese Informationen dann für die Speicherung weiterleitet. Eine weitere Schwierigkeit besteht in der Übersetzung der deutschen Nachrichten ins Englische, da für die Analyse KI-Modelle zum Einsatz kommen, die oft auf englische Texte ausgerichtet sind. + + Zusätzlich muss der Unternehmensname standardisiert werden, sodass bei unterschiedlichen Schreibweisen dennoch dasselbe Unternehmen erkannt wird und die gewonnenen Informationen zu diesem Unternehmen angezeigt werden können. Beispielsweise wird in Artikeln häufig von VW, Volkswagen, Volkswagen AG oder dem Volkswagen Konzern gesprochen, was alles dasselbe Unternehmen repräsentiert. + +Die Prämissen für die Lösungstechnologie lauten: + +- Auswahl einer Technologie zur automatisierten Auswertung von Unternehmensdaten in Nachrichten. +- Automatisierte Analyse der Stimmung in Bezug auf ein Unternehmen in den Nachrichten. +- Übersetzen der Texte ins Englische +- Standardisierung der Unternehmensnamen. +- Die Technologie sollte kostenlos und frei verfügbar sein. +- Die Technologie sollte mit Python kompatibel sein + +### Verflechtungsanalyse +Die Verflechtungsanalyse konzentriert sich auf die Auswertung von Daten in Form eines Netzwerks, in dem Unternehmen und Akteure mit ihren Verbindungen zu anderen dargestellt werden. Ziel ist es, Gruppierungen zu identifizieren, die für weitere Analysen relevant sind. Diese Aspekte werden in den Kapiteln 3.5 und 4.5.2 näher erläutert. + +Es wird daher nach einem Werkzeug gesucht, das die Akteure mit ihren Beziehungen visualisiert. Dabei ist es wichtig, dass das Tool die Positionen der Knoten und Kanten berechnet, um Überlappungen zu vermeiden. Bei großen Datenmengen können Performanzprobleme auftreten, die zu einer längeren Generierung führen. Das Tool sollte darauf ausgelegt sein, solche Probleme zu minimieren. Darüber hinaus muss es Metriken für die Analyse der Beziehungen berechnen können. Zusätzlich soll die Visualisierung des Tools in die grafische Benutzeroberfläche der Anwendung integrierbar sein. + +Demnach ergeben sich folgende Anforderungen: + +- Integration mit dem Visualisierungstool. +- Performante Berechnung der Positionen der Knoten und Kanten. +- Berechnung der klassischen Metriken für die Netzwerkanalyse. +- Visualisierung des Netzwerkgeflechts. +- Benutzerfreundlichkeit. +- Die Technologie sollte kostenlos und frei verfügbar sein. +- Die Technologie sollte mit Python kompatibel sein + +### Visualisierung +Nachdem sich die anderen Bereiche um die Zulieferung und Aufbereitung der Daten gekümmert haben, steht in der Visualisierungsphase die Auswahl eines Frameworks für die ansprechende Darstellung der Ergebnisse im Fokus. Dies beinhaltet die Auswahl eines Frontends, das in der Lage ist, Daten in ansprechenden Grafiken zu präsentieren. Das Frontend soll auf Python basieren und webserverfähig sein. Zusätzlich sollte es benutzerfreundlich sein und nahtlos in die Netzwerkanalyse integriert werden können. + +Die formulierten Anforderungen sind demnach: + +- Auswahl eines benutzerfreundlichen Frontends. +- Das Framework sollte die Erstellung von Grafiken ermöglichen. +- Das Framework sollte die Darstellung eines Netzwerks unterstützen. +- Das Framework sollte webserverfähig sein. +- Das Framework sollte auf Python basieren. +- Die Technologie sollte kostenlos und frei verfügbar sein. + +### Provisionierung +Die Provisionierung befasst sich mit der Bereitstellung der entstehenden Anwendung für die Benutzer. Dabei soll die Anwendung über das Internet erreichbar sein, jedoch durch ein Passwort geschützt werden. Aus finanziellen Gründen ist das Hosting kostenfrei und erfolgt über Container. Das Projektteam hat sich für den Container-Ansatz entschieden, um die Anwendung auf mehrere kleine Teilanwendungen zu verteilen. Diese können separat getestet und von einzelnen Projektentwicklern auch lokal ausgeführt werden. + +Daraus ergeben sich die folgenden Prämissen: + +- Auswahl einer Technologie für das Hosting mit Docker/Container. +- Kostenfreiheit. +- Zugriff über das Internet für alle Projektteilnehmer mit Passwortschutz. + +## Lösungsansätze: Überblick über relevante Technologien und Werkzeuge +Auf Basis der im vorherigen Kapitel festgelegten Prämissen erfolgt in diesem Abschnitt eine kurze Beschreibung der verfügbaren Technologien, gefolgt von der Auswahl der für dieses Projekt geeigneten Technologien. Wie bereits erwähnt, können detailliertere Informationen den Zwischenberichten im folgenden Kapitel 3 entnommen werden. + +### DevOps +Basierend auf den oben beschriebenen Anforderungen besteht die Wahl zwischen GitHub und GitLab als Versionsverwaltungstool. Es wird auch entschieden , ob eine öffentliche Organisation verwendet wird, die Fachhochschule das Tool hostet oder ob es über einen Home Server erfolgt. + +Nach sorgfältiger Prüfung der vorhandenen Optionen wurde die Entscheidung für die Lösung mit GitHub über die GitHub-Organisation der Fachhochschule getroffen. Diese Lösung ist naheliegend, da bereits alle Projektteilnehmenden einen GitHub-Account besitzen und gleichzeitig den Professoren und der Fachhochschule Zugriff auf den Quellcode gewährt werden kann. Darüber hinaus bleibt der Quellcode in der Verwaltung der Fachhochschule und kann späteren Studierenden zur Verfügung gestellt werden. + +Diese Entscheidung bringt für das Projekt weitere Vorteile mit sich, da keine zusätzlichen Kosten entstehen. Im Hinblick auf DevOps bietet GitHub mit GitHub Actions eine ausgezeichnete Möglichkeit, eigene Pipelines zu erstellen, diese automatisch auszuführen und über bestimmte Hooks zu triggern. So kann beispielsweise beim Push auf einen Branch die Pipeline gestartet werden. + +GitLab steht über die Fachhochschule nicht zur Verfügung und bedeutet somit einen größeren Mehraufwand für das Projekt. + +### Text Mining +Für das Text Mining konnte kein einsatzbereites, kostenloses Tool gefunden werden, das alle Anforderungen erfüllt. Daher wurde die Entscheidung getroffen, einen eigene Lösung zu entwickeln, der die erforderlichen APIs abfragt und die Daten entsprechend aufbereitet. Der Quellcode wurde in Python verfasst, und die genaue Vorgehensweise wird ausführlich im Kapitel 3.2 beschrieben. + +### Datenspeicherung +Für die Datenspeicherung steht die gesamte Palette an SQL- und NoSQL-Datenbanken zur Verfügung. Basierend auf dem Kenntnisstand der Projektteilnehmer wird die Entscheidung getroffen, für den Data Lake die NoSQL-Datenbank MongoDB zu verwenden. Diese steht kostenfrei zur Verfügung, kann in Docker-Containern gehostet werden und eignet sich aufgrund ihres schemenlosen Designs gut für die unstrukturierte Speicherung von zahlreichen Daten. Außerdem kann über MongoDB Atlas eine kostenlose global verfügbare Instanz bezogen werden. + +Für die aufbereiteten Daten wird, ebenfalls aufgrund des Kenntnisstands der Studierenden, PostgreSQL ausgewählt. Dies ist eine SQL-Datenbank, die ebenfalls in einem Docker-Container gehostet werden kann und einfach zu bedienen ist. Das Schema sowie weitere Details sind im Kapitel 3.3 nachzulesen. + +Beide Technologien sind kostenfrei zugänglich und können mithilfe verfügbarer Bibliotheken leicht über Python angesprochen werden. + +### Sentimentanalyse +Bei der Sentimentanalyse besteht eine kleinere Auswahl an möglichen Ansätzen bereit. Diese stellt unter anderem den KI Anteil des Projektes dar, weshalb hier die Analyse mithilfe eines Modells stattfindet. + +### Verflechtungsanalyse +Für das Netzwerktool der Verflechtungsanalyse stehen mehrere Optionen zur Auswahl, darunter [NetworkX](https://networkx.org/), Scatter Graphen, NetworkX mit [Pyvis](https://pyvis.readthedocs.io/en/latest/), [Graphviz](https://graphviz.org/) und [Cytoscape](https://cytoscape.org/). Jedes dieser Frameworks hat seine Vor- und Nachteile. Cytoscape bietet beispielsweise ansprechende Visualisierungen, während Graphviz eine benutzerfreundliche Schnittstelle zur Erstellung von Graphen und Netzwerken bietet. Dennoch ließ sich NetworkX am besten integrieren. Es zeichnet sich durch eine einfache Bedienung aus und kann Metriken direkt berechnen. Im Vergleich dazu erfordert Graphviz, dass der Graph zuerst durch eine Methode in einen NetworkX-Graphen konvertiert wird, was zusätzliche Arbeit bedeutet. + +Die Visualisierung mit Pyvis stellt die schönste Darstellung dar, da dem Nutzer direkte Interaktionen ermöglicht werden. Dieser kann die Nodes weiter auseinander ziehen oder in einzelne Bereiche hineinzoomen. Die Herausforderung besteht jedoch darin, dass bei großen Datenmengen die Generierung erheblich verlangsamt wird und teilweise Minuten dauert. Ein weiterer Nachteil besteht darin, dass Pyvis eine HTML-Seite mit JavaScript erstellt, die nicht nahtlos in das gewählte Visualisierungstool eingebunden werden kann. Es kann lediglich über ein IFrame eingefügt werden, was die Performance erheblich beeinträchtigt. + +Daher wurde die Entscheidung getroffen, auf das native NetworkX zurückzugreifen, das mithilfe eines Plotly Scatter Graphen visualisiert wird. Hierbei werden die Positionen aus dem NetworkX-Graphen ausgelesen und in Punkte für einen Scatter Graphen transformiert. + +### Visualisierung +Für das Visualisierungstool stehen verschiedene Optionen zur Auswahl, darunter Plotly Dash, Django sowie Webframeworks auf JavaScript-Basis wie Angular oder Vue.js. Da die Kenntnisse im Team hauptsächlich auf Python basieren, wurde sich trotz der vielen Vorteile von JavaScript-Frameworks gegen diese entschieden. + +Schließlich wird aufgrund des vorhandenen Kenntnisstands und der geringeren Komplexität die Wahl auf Plotly Dash getroffen. Dieses Tool ist darauf ausgelegt, einfache Anwendungen für die Visualisierung von Graphen und Daten zu erstellen. Es kann zudem in einem Container gehostet werden und verwendet Python als Programmiersprache. + +Die Einarbeitung in Django wäre erheblich umfangreicher und wurde daher zugunsten von Plotly Dash verworfen. + +### Provisionierung +Bei der Provisionierung gilt es, zwischen der Nutzung eines der Hyperscaler (AWS, GCP oder Azure) mit ihren kostenfreien Kontingenten oder der Eignung der Server der Universität Südwestfalen zu unterscheiden. Als letzte Alternative besteht die Möglichkeit des Selbsthostings, wobei dies aufgrund des Aufwands, einen eigenen Server einzurichten und abzusichern, wirklich nur als allerletzte Option betrachtet wird. + +Nach mehreren Gesprächen ergab sich die Möglichkeit, den Container-Cluster der Fachhochschule zu nutzen, was sich als kostengünstige Option für das Projekt herausstellte. Die Entscheidung fiel daher schnell. Obwohl das Hosting über einen Public Cloud Provider ebenfalls die Anforderungen erfüllt, birgt es das Risiko, dass eine Kreditkarte angegeben wird und bei Fehlverhalten oder falschen Einstellungen in der Cloud erhebliche Kosten verursacht werden können. Zudem ist das Team in Bezug auf Cloud-Ressourcen begrenzt geschult. Daher wurde eindeutig die Lösung des FH-Clusters bevorzugt. + +## Proof-of-Concept mit Jupyter Notebooks +Die in diesem Abschnitt beschriebene Recherche ist am Projektbeginn durchgeführt worden in dem auf Basis der Prämissen für die einzelnen kategorien Jupyternotebooks erstellt wurden um die Technologien zu evaluieren und einen Eindruck für den Aufwand des Prjektes zu erhalten. + +Dieses Vorgehen bezeichnet man als Proof-of-Concept (POC) und reduziert spätere Arbeitsaufwände die entstehen, wenn sich durch fehlende Evaluation für falsche Technologien oder Konzepte entschieden wurde. + +Die Jupyternotebooks finden sich im Projekt unter den Ordnern +- [research](documentations/research) +- [Jupyter](Jupyter) diff --git a/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S3.md b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S3.md new file mode 100644 index 0000000..b6b7ce8 --- /dev/null +++ b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S3.md @@ -0,0 +1,4 @@ +# Grundlagen und Basistechniken (Tim Ronneburg) +In diesem Abschnitt sind die Zwischenberichte des Projekts zu finden. In diesen Berichten wurde die Recherche zu den einzelnen Kategorien durchgeführt und in den entsprechenden Jupyter Notebooks im Git-Repository bewertet. Dieses Kapitel präsentiert eine detaillierte Analyse der zuvor beschriebenen Recherche mit zusätzlichen Begründungen und Erläuterungen, warum bestimmte Technologien, Konzepte und Vorgehensweisen für das Projekt ausgewählt wurden. + +Es ist zu beachten, dass die Zwischenberichte zu einem frühen Zeitpunkt des Projektes erstellt wurden und eine Hausarbeit darstellen, weshalb in einigen Abschnitten von zukünftigen Vorgehensweisen und Ausblick gesprochen wird. \ No newline at end of file diff --git a/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S4-5-2.md b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S4-5-2.md new file mode 100644 index 0000000..479d62f --- /dev/null +++ b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S4-5-2.md @@ -0,0 +1,64 @@ +# Netzwerkanalyse (Tim Ronneburg) +In diesem Abschnitt wird die Umsetzung der Netzwerkanalyse behandelt, die den Aufbau und die Analyse eines Netzwerks gemäß den im Kapitel 3.5 erwähnten Verflechtungsanalysen betrifft. + +Wie bereits im vorherigen Abschnitt erläutert, kommt im Rahmen des Projekts Plotly Dash zum Einsatz, ein Tool, das für die Erstellung von Dashboards mit Python entwickelt wurde. Zusätzlich wird dieses Tool um die Bibliothek NetworkX erweitert, um Netzwerkgraphen darzustellen. + +Die Netzwerkanalyse wird an verschiedenen Stellen im Projekt integriert. Zunächst auf der Hauptseite, wo der gesamte Graph dargestellt wird, dann auf der Unternehmensdetailseite zur Untersuchung der Verflechtungen aus der Perspektive des ausgewählten Unternehmens, sowie auf der Personendetailseite aus dem gleichen Grund wie auf der Unternehmensseite. + +Quellcode-seitig werden mehrere Dateien für die Erstellung des Netzwerks erzeugt. Im Verzeichnis "UI" befindet sich ein Unterordner "utils" mit dem weiteren Unterordner "networkx", in dem die Dateien zu finden sind: +- [network_2d.py ](src/aki_prj23_transparenzregister/utils/networkx/network_2d.py) +- [network_3d.py](src/aki_prj23_transparenzregister/utils/networkx/network_3d.py) +- [network_base.py](src/aki_prj23_transparenzregister/utils/networkx/network_base.py) +- [networkx_data.py](src/aki_prj23_transparenzregister/utils/networkx/networkx_data.py) + +Die ersten beiden Dateien enthalten den Quellcode für die Visualisierung des Netzwerks mithilfe eines Scatterplots in 2D oder 3D. Die Datei "base" umfasst die Initialisierung des Netzwerks anhand der ausgewählten Daten. Hierbei werden gleichzeitig die relevanten Metriken gebildet. In der Datei "data" sind verschiedene Funktionen enthalten, die dazu dienen, Daten abzurufen, welche anschließend dem Netzwerk zugeführt werden können. + +Die "base"-Datei legt somit den Grundstein für das Netzwerk, indem sie nicht nur die Struktur initialisiert, sondern auch wichtige Metriken generiert. Die "data"-Datei hingegen stellt eine Schnittstelle dar, durch die das Netzwerk mit den benötigten Daten versorgt wird, wobei diverse Funktionen zur Datenabfrage integriert sind. + +Der Ablauf gestaltet sich unter anderem wie folgt: Wenn ein Nutzer die Startseite aufruft, werden bestimmte Funktionen in "networkx_data" ausgeführt, um die Datenbank nach den voreingestellten Informationen zu durchsuchen. Diese Daten werden aufbereitet und als Pandas DataFrame an "network_base" übergeben, wo mithilfe des Frameworks NetworkX ein Graph erstellt wird. In diesem Graph-Element sind die Positionen der Nodes enthalten. Zusätzlich werden Methoden bereitgestellt, um Standard-Netzwerkanalysemetriken zu berechnen. Für dieses Projekt handelt es sich dabei um die Metriken "degree", "betweenness", "closeness" und "pagerank". + +Anschließend werden das NetzwerkX-Objekt und das DataFrame "Metrics" an die Datei "network_xd" übergeben. Diese Datei liest die Positionen der Nodes aus, berechnet die Edges und erstellt dann mithilfe eines Scatterplots den Graphen in 2D beziehungsweise 3D. Das Ergebnis ist ein Figure-Objekt, das von Dash angezeigt werden kann. + +Dieses Figure Objekt wird in den folgenden Pages Dateien eingebunden: +- home.py +- company_elements.py +- person_elements.py + +Für das Aktualisieren des Netzwerks nach Benutzereingaben werden Callbacks verwendet. Diese werden durch die Interaktion mit einem HTML-Element wie einem Dropdown oder Radiobuttons ausgelöst. Da dem Benutzer mehrere Auswahlmöglichkeiten für die Betrachtung des Netzwerks gegeben werden, muss der Callback für das Netzwerk mehrere Inputs aufnehmen und verarbeiten. Dies ist erforderlich, da ein Callback immer nur einen Output haben kann und mehrere Callbacks nicht auf dasselbe HTML-Element verweisen sollten. Obwohl es mittlerweile eine Möglichkeit gibt, mehrere Outputs zu nutzen, bietet dies keine signifikanten Vorteile weshalb in diesem Projekt darauf verzichtet wurde. + +## Bedienung des Netzwerks auf der Homepage +Die Homepage des Transparenzregisters sieht zur Vollendung des Projektes folgender Maßen aus: +![Abbildung der Homepage](images/Home_page.PNG) + +Auf der linken Seite befindet sich eine Tabelle mit den 10 "besten" Nodes aus dem Links abgebildetet Graphen. Mit "besten" sind hier die 10 Nodes mit dem höchsten Wert der oberhalb der Tabelle gewählten Metrik. Je nach gefilterten Daten ändert sich die Tabelle automatisch und zeigt immer den aktuellen Stand zum rechts erstellten Graphen. + +Der Graph auf der rechten Seite repräsentiert die Verflechtung von Unternehmen und Akteuren. Dabei stellen orangene Punkte Personen wie Wirtschaftsprüfer oder Geschäftsführer dar, während dunkelgrüne Punkte Unternehmen symbolisieren. Die Bedienung des Graphen erfolgt über die oberen Bedienfelder. Die ersten beiden Dropdown-Menüs ermöglichen die Auswahl der Datenbasis, auf die sich der Graph beziehen soll. Hierbei ist auch eine Mehrfachauswahl möglich. Neben den Daten kann auch das Layout des Graphen eingestellt werden, wobei für die dreidimensionale Darstellung nur begrenzte Optionen verfügbar sind. + +Die initiale Erstellung eines Graphen kann mehrere Sekunden in Anspruch nehmen, wird jedoch anschließend zwischengespeichert und kann in den nächsten 30 Minuten schneller durchgeführt werden. Die anfänglichen Leistungsprobleme resultieren aus der Menge an Daten, die abgerufen, verarbeitet und dargestellt werden müssen. Das Zusammenspiel von Datenbank, NetworkX und Plotly beeinflusst hier die Gesamtperformance. + +## Bedienung des Netzwerks auf der Company Page +Nach Auswahl eines bestimmten Unternehmens kann auf der Unternehmensseite der Reiter "Verflechtung" gewählt werden, um die Verflechtungen des Unternehmens zu betrachten. Sollte das ausgewählte Unternehmen keine Verflechtungen aufweisen, wird dem Nutzer ein entsprechender Hinweistext angezeigt. Im Bild rot makiert. + +![Abbildung eines Hinweis Textes](images/Company_note.PNG) + +Bei ausreichend vorhandenen Daten wird ein kompakter Graph erstellt, der die Verflechtungen des betrachteten Unternehmens zeigt. Hierbei werden lediglich die engsten Verbindungen visualisiert. Auf dieser Seite ist keine Interaktion mit dem Graphen vorgesehen, da der Benutzer hier lediglich zusätzliche Informationen zum Unternehmen erhalten soll, ohne den gesamten Graphen durchzugehen. Diese Funktion ist für die Homepage vorgesehen. + +![Abbildung der Companypage](images/Company_page.PNG) + +## Bedienung des Netzwerks auf der Person Details Page +Die Personen-Detailseite verhält sich in Bezug auf das Netzwerk analog zur Unternehmensseite. Auch hier erhält der Nutzer lediglich zusätzliche Informationen zur Person, kann jedoch nicht weiter mit dem Graphen interagieren. + +Auf der Personen-Seite werden die Verflechtungen bis zur dritten Ebene abgebildet, und die jeweilige Anzahl der Verbindungen wird oben in den Containern mit den Kennzahlen dargestellt. + + +## Ausgelassene Features +Im Kapitel 3.5 wurden neben den hier beschriebenen Funktionen auch weitere Aspekte betrachtet und evaluiert, insbesondere im Hinblick auf die Darstellung und Analyse unternehmerischer Kennzahlen wie EBIT, Umsatz, Gewinn, Aktienkurs usw. . Leider konnten im Zuge der Datenerfassung die hierfür benötigten Daten nicht zuverlässig und in ausreichender Menge generiert werden. Dies führte dazu, dass diese Funktionen aus dem Verflechtungsscope herausgenommen wurden. + +Ein weiterer Herausforderungspunkt war die schwierige und performante Einbindung des Graphen in Plotly Dash. Die Generierung des Graphen bei größeren Datenmengen dauerte mit dem ursprünglich ausgewählten Tool deutlich länger, als es in den Proof-of-Concepts den Anschein erwecken ließ. Daher erfolgte eine Umstellung auf eigens erstellte Scatter Plots, für die ein eigener Algorithmus entwickelt werden musste, der die Positionen aus dem NetworkX ausließt und in Punkte für den Scatter Graphen formatiert. Dies hatte einen deutlichen Einfluss auf die Entwicklung und führte zu Verzögerungen. + +Zuletzt ist die Verflechtungsanalyse einer der Bereiche, die abhängig von den Ergebnissen anderer Kategorien ist. Dies bedeutet, dass die Entwicklung mit konkreten Daten erst versetzt beginnen konnte, was den Raum für Fehlerbehebungen und zusätzliche Funktionen zusätzlich begrenzt hat. + +## Kurzes Resumee der Verflechtungsanalyse/Netzwerkanalyse +Alles in allem konnte ein Netzwerk auf Basis der Unternehmensdaten erstellt werden, das Einblicke in die Verzweigungen einiger Unternehmensbeziehungen ermöglicht. Die Analyse wird dabei von klassischen Netzwerkanalyse-Kennzahlen unterstützt. Jedoch muss die Analyse weiterhin durch den Benutzer erfolgen und ist nur in einem eingeschränkteren Maße, als ursprünglich angedacht, durchführbar. Die Analyse hinsichtlich unternehmerischer Kennzahlen musste aufgrund mangelnder Daten aus dem Projekt ausgeschlossen werden. + +Die Möglichkeit, ein Netzwerk basierend auf den vorliegenden Unternehmensdaten zu generieren, bietet einen Einblick in die Verästelungen bestimmter Unternehmensbeziehungen. Die Analyse wird durch klassische Netzwerkanalyse-Kennzahlen unterstützt. Dennoch ist die Durchführung der Analyse auf eine begrenztere Ebene beschränkt als ursprünglich geplant. Aufgrund unzureichender Daten im Projekt musste die Analyse bezüglich unternehmerischer Kennzahlen ausgeschlossen werden. \ No newline at end of file diff --git a/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Company_note.PNG b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Company_note.PNG new file mode 100644 index 0000000..17521ca Binary files /dev/null and b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Company_note.PNG differ diff --git a/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Company_page.PNG b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Company_page.PNG new file mode 100644 index 0000000..79a9458 Binary files /dev/null and b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Company_page.PNG differ diff --git a/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Home_page.PNG b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Home_page.PNG new file mode 100644 index 0000000..ec111dc Binary files /dev/null and b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/Home_page.PNG differ diff --git a/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/unterschrift.PNG b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/unterschrift.PNG new file mode 100644 index 0000000..ee80af4 Binary files /dev/null and b/documentations/Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/images/unterschrift.PNG differ diff --git a/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Betweenness.PNG b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Betweenness.PNG new file mode 100644 index 0000000..975a416 Binary files /dev/null and b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Betweenness.PNG differ diff --git a/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Closeness.PNG b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Closeness.PNG new file mode 100644 index 0000000..866f412 Binary files /dev/null and b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Closeness.PNG differ diff --git a/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Degree.PNG b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Degree.PNG new file mode 100644 index 0000000..cd78b28 Binary files /dev/null and b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Degree.PNG differ diff --git a/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Eigenvector.PNG b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Eigenvector.PNG new file mode 100644 index 0000000..570e59b Binary files /dev/null and b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Eigenvector.PNG differ diff --git a/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Graph.PNG b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Graph.PNG new file mode 100644 index 0000000..402386a Binary files /dev/null and b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Graph.PNG differ diff --git a/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Transparenzregister_Graph.PNG b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Transparenzregister_Graph.PNG new file mode 100644 index 0000000..ff093e1 Binary files /dev/null and b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/Transparenzregister_Graph.PNG differ diff --git a/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/unterschrift.PNG b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/unterschrift.PNG new file mode 100644 index 0000000..319b9b5 Binary files /dev/null and b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/abbildungen/unterschrift.PNG differ diff --git a/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/verflechtungsanalyse.md b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/verflechtungsanalyse.md new file mode 100644 index 0000000..63173d0 --- /dev/null +++ b/documentations/Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/verflechtungsanalyse.md @@ -0,0 +1,843 @@ +--- +author: +- | + Tim Ronneburg + Fachhochschule Südwestfalen\ + Schriftliche Ausarbeitung im Modul\ + „Projektgruppe"\ + im Studiengang\ + M.Sc. Angewandte Künstliche Intelligenz\ + eingereicht bei\ + Prof. Dr.-Ing. Doga Arinir +bibliography: +- literatur/literatur.bib +title: Verflechtungsanalyse des Transparenzregisters +--- + +# Verflechtungsanalyse des Transparenzregisters +## Erklärung + +Ich erkläre hiermit, dass ich die vorliegende Arbeit selbstständig +verfasst und dabei keine anderen als die angegebenen Hilfsmittel benutzt +habe. Sämtliche Stellen der Arbeit, die im Wortlaut oder dem Sinn nach +Werken anderer Autoren entnommen sind, habe ich als solche kenntlich +gemacht. Die Arbeit wurde bisher weder gesamt noch in Teilen einer +anderen Prüfungsbehörde vorgelegt und auch noch nicht veröffentlicht. + +2023-10-01 + +image + +Tim Ronneburg + +## Einleitung + +In den letzten Jahren mehren sich die großen Wirtschaftsskandale, in +denen Unternehmen Bilanzen fälschen oder untereinander zusammenarbeiten, +um Steuerschlupflöcher auszunutzen, wie bei Wirecard oder der Cum-Ex +Affäre. Ein wichtiger Bestandteil für das Erkennen oder Aufarbeiten +solcher Skandale besteht darin, sich einen Überblick über die +Verflechtungen der beteiligten Akteure zu verschaffen. Diese Arbeit +resultiert aus einem Projekt, welches genau solche Verflechtungen +transparent darzustellen versucht. Bei dem sogenannten +Transparenzregister werden die Beziehungen von Unternehmen und einzelnen +natürlichen Personen wie Wirtschaftsprüfer, Kommanditisten etc. aus +Deutschland und der Europäischen Union dargelegt. + +### Problemstellung + +Die angesprochenen Verflechtungen sind teilweise komplexe Strukturen von +Unternehmen und anderen Akteuren, die sich erst bei einer umfassenderen +Betrachtung erkennen lassen. Die Analyse solcher Konstrukte ist aus den +reinen Rohdaten, ohne aufwendiger Aufarbeitung und Visualisierung, +nahezu unmöglich. Damit aus den Daten Informationen und Wissen gewonnen +werden können, müssen diese aufbereitet und in einer verständlichen Form +dargestellt werden. Spätestens seit der F8 von Facebook im Jahr 2007 ist +die Nutzung von Graphen für solche Verflechtungen etabliert. Eine solche +Verflechtung nennt man ein *Social Network*, *Social Graph* oder auch +*Sociogram*. Mit diesem Graph können Analysen einfacher durchgeführt +werden, da sowohl das Wissen aus der Graphentheorie zum Tragen kommt als +auch die Beziehungen einzelner Akteure mit dem bloßen Auge ersichtlich +sind. + +### Zielsetzung und Aufbau der Arbeit + +Ziel dieser Arbeit ist die Vermittlung der Grundlagen für eine solche +Verflechtungsanalyse. Es wird aufgezeigt, wie ein solcher Graph +aufgebaut werden kann, welche Bedingungen gelten und welche Kennzahlen +man berechnen kann. + +Das Werk beginnt mit einer Einführung in die Graphentheorie, aus dieser +leiten sich *Social Networks* beziehungsweise *Social Graphs* ab. Neben +der Graphentheorie wird auch auf die Analyse von *Social Networks* +eingegangen. Im Hauptteil werden diese Grundlagen auf das zugrunde +liegende Projekt angewendet. Es wird verdeutlicht, wie ein solcher Graph +für das Projekt aufgebaut wird und welche Bedingungen dafür erfüllt sein +müssen. Des Weiteren werden Kennzahlen vorgestellt und gebildet mithilfe +derer die Analyse einer solchen Verflechtung durchgeführt werden kann. + +Abgeschlossen wird diese Arbeit mit einer Handlungsempfehlung für das +Projekt sowie einem Fazit und Ausblick. + +## Graphentheorie + +In diesem Abschnitt werden die Grundlagen der Graphentheorie erläutert. +Mithilfe dieses Wissen lassen sich Verflechtungen besser verstehen und +analysieren, da auch Verflechtungen Graphen sind. + +### Begriffliche Definition + +Graphen sind nach der Graphentheorie "Strukturen aus Punkten und +Verbindungen zwischen diesen Punkten" [1]. Die +Punkte werden als **Ecken/Knoten** oder im Englischen ***Nodes*** und +die Verbindungen als **Kanten/Verbindungen**, oder im Englischen +***Edges*** bezeichnet. Dabei liegt der Kern eines Graphen nicht in der +Visualisierung, sondern in dessen mengentheoretischen Eigenschaften. +[1] + +Es gibt diverse Arten von Graphen: **Ungerichtete Graphen** und +**gerichtete Graphen** beziehungsweise **Digraphen**. Für ungerichtete +Graphen gilt folgende Definition: + +*"Ein ungerichteter Graph $G$ ist ein Paar ($V$, $E$). Hierbei ist $V$ +eine endliche Menge, welche die Ecken repräsentiert, und $E$ ist eine +Menge, die aus Mengen der Form $v1$, $v2$ besteht, wobei $v1$, $v2$ +$\in$ $V$ gilt. $E$ repräsentiert die Menge der Kanten."* +[1] + +Anhand dieser Definition lassen sich Graphen mit beliebig vielen Kanten +zwischen den Ecken bilden. Die Kanten müssen dabei nicht geradlinig +verlaufen, sodass derselbe Graph auf verschiedene Weisen dargestellt +werden kann. [1] + +Im Gegensatz dazu besitzen gerichtete Graphen Kanten mit einer +vorgegebenen Richtung. Diese Richtung wird anhand eines Pfeiles auf der +Kante visualisiert. Auch ein gerichteter Graph kann auf verschiedene +Arten dargestellt werden. Eine mögliche Definition von gerichteten +Graphen ist die folgende: + +*"Ein gerichteter Graph oder Digraph $D$ ist eine Struktur ($V$, $E$). +Hierbei ist $V$ eine endliche Menge der Ecken und $E$ ist eine Menge, +die aus Paaren der Form ($v1$, $v2$) besteht, wobei $v1$, $v2$ $\in$ $V$ +gilt. E repräsentiert die Menge der gerichteten Kanten, welche auch +Bögen genannt werden."* [1] + +Die bereits angesprochene Möglichkeit, einen Graphen mit denselben +Eigenschaften auf unterschiedlichste Weise darzustellen, bezeichnet man +als **Isomorphie**. Es ist einfach von einem Graph einen isomorphen +Graphen zu erzeugen, aber deutlich komplexer die Isomorphie von zwei +Graphen festzustellen. [2] + +### Sociogram/ Social Network/ Social Graph + +Ein Sociogram ist ein Model eines Netzwerks von sozialen Verbindungen +die durch einen Graphen repräsentiert werden. Diese Idee wurde 2007 von +Facebook als Social Graph in der F8 vorgestellt. Diese Art von Graph +basiert auf der Graphentheorie. Die Stärken dieses Graphen liegen in der +Veranschaulichung der sozialen Verflechtungen. + +Ein solcher Graph oder ein solches Netz wird aufgebaut, indem jede Ecke +des Graphen einen Akteur (Person oder Unternehmen), jede Kante eine +Verbindung (Beauftragung, Verwandschaft, Arbeitsverhältnis) darstellt. +Die Kanten können mit Gewichten versehen werden. Jede Kante ist dabei +gerichtet.[3] + +Das Ergebnis kann als *Social Graph, Social Network* oder *Sociogram* +bezeichnet werden. In dieser Arbeit wird hauptsächlich der Begriff +*Social Network* (SN) genutzt. + +Die kleinste Struktur in einem *Social Network* wird als *Dyad* +bezeichnet und ist eine soziale Gruppe bestehend aus zwei Knoten mit +einer gerichteten oder ungerichteten Kante. Die nächst größere Form ist +eine *Triad*, welche offen oder geschlossen sein kann. Offen bedeutet, +dass über einen Knoten die anderen beiden verbunden sind. Hingegen ist +bei einer geschlossenen *Triad* jeder Knoten mit beiden anderen Knoten +über eine Kante verbunden. Die größte soziale Gruppe stellt ein *Quad* +dar und besteht aus vier Ecken.[4] + +Die Ansammlung von mehreren Akteuren durch enge Verbindungen wird als +***Cluster*** oder ***Group*** bezeichnet. + +### Social Network Analysis (SNA) + +Bei der *Social Network Analysis* (SNA) werden die sozialen Strukturen +anhand von Metriken aus der Graphentheorie untersucht. + +Eine Analysemöglichkeit ist die Bestimmung der *number of hops*. Diese +gibt an, wie viele Verbindungen benötigt werden, um von einem Punkt zu +einem anderen zu gelangen. Dieser Wert kann auf einen Teil des Graphen +sowie auf den gesamt Graphen gemittelt werden. Ist der Median der +*number of hops* im Gesamtgraphen beispielsweise bei 5, so werden +Verbindungen, die diesen Schwellwert überschreiten, zu einem Cluster +kombiniert. [3] + +Weitere Einsichten werden über ein Netzwerk erlangt, in dem man Teile +des Netzwerkes oder das gesamte Netzwerk in drei verschiedene Level +abstrahiert. **Element-Level** ist die Betrachtung der Auswirkungen und +Einflüsse einzelner Ecken und Kanten. **Group-Level** analysiert die +Zusammenhänge und Dichte von Gruppen innerhalb des Netzes. +**Network-Level** ist das Interesse an den topologischen Eigenschaften +des Netzwerks. [5] + +#### Element-Level Metriken + +Die folgenden Metriken sind aus der Element-Level Analyse und betrachten +die Bedeutung der einzelnen Knoten und Kanten. + +Metriken zur Bedeutung von Verbindungen: + +**Transitive** beschreibt die Menge an gleichen Kanten zweier Ecken, die +über eine Kante verbunden sind. In einem sozialen Netzwerk für Personen +gibt es die Wahrscheinlichkeit, dass zwei Bekannte einer Person sich +anfreunden. + +**Reciprocity** gibt die Wahrscheinlichkeit an, mit der sich eine Ecke +mit sich selbst verbindet. + +**Assortativity** drückt aus, wie sehr sich ein Akteur mit anderen +Akteuren verbindet, die ähnlich sind hinsichtlich der Größe des Grades. + +**Homophily** ist die Wahrscheinlichkeit von Verbindungen sehr ähnlicher +Akteure untereinander. [5] + +Weitere Algorithmen und Kennzahlen sind die Folgenden: + +**Degree Centrality** gibt die Anzahl der Kanten je Knoten an. Knoten +mit einer hohen *Degree Centrality* haben die meisten Verbindungen und +können einen hohen Einfluss aufweisen oder gut platziert sein. Es wird +eingesetzt, um gut verbundene, beliebte, informationshaltende oder +Reichweiten starke Akteure zu finden. Die Kennzahl kann bei *directed +graphs* in ***in-degree*** (eingehende) und ***out-degree*** +(ausgehende) Kanten aufgeteilt werden.[@NetworksAnIntro vgl. S. 168-169] + +Ein Graph kann nach und nach immer weiter nach der *Degree Centrality* +gefiltert werden. Dadurch erhält man die am besten verbundenen Ecken. +Dieses Vorgehen bezeichnet man als ***degenerate graph*** oder +***Degeneracy***. + +Um diesen Wert zu berechnen benötigt es lediglich die ausgehenden Kanten +an den jeweiligen Ecken zu berechnen. Um einen standardisierten Wert zu +berechnen, nimmt man die Anzahl an Ecken je Graph (n) und nutzt die +Summe minus 1 (n-1) als Teiler für den Wert der Kanten je Ecke. Wenn ein +Graph 10 Ecken hat und eine Beispiel-Ecke 5 ausgehende Kanten, ergibt +sich daraus eine *Degree Centrality* von 5 und ein standardisierter Wert +von 1/3 (3/(10-1)). + +Im Zusammenhang des Transparenzregisters lassen sich mit diesen +Kennzahlen gut vernetzte Unternehmen oder Akteure mit großer Reichweite +ermitteln. + +**Betweenness Centrality** hebt Knotenpunkte hervor, welche besonders +oft als Verbindungsknoten zwischen zwei anderen Einheiten dienen. Sie +werden als \"Brücken\" benutzt und können der kürzeste Pfad in einem +Netzwerk sein. Mit dieser Kennzahl werden die Akteure gefunden, die den +Fluss des Netzwerks am meisten beeinflussen. Bei der Interpretation +dieser Kennzahl muss allerdings mit Vorsicht agiert werden. + +Eine hohe *Betweeness Centrality* kann ausdrücken, dass ein Akteur einen +großen Einfluss und Autorität über einen Cluster im Netzwerk verfügt, es +kann jedoch auch sein, dass der Akteur nur als Vermittler beider Enden +dient. [7] + +Dieser Wert lässt sich dadurch berechnen, indem jedes Ecken-Paar des +Netzwerkes genommen wird und die Anzahl der zwischen ihnen liegenden +Ecken auf dem kürzesten Weg gezählt werden (*geodesic distance*). Man +zählt dann, wie oft ein Knoten als \"Brücke\" fungiert. + +Beim Transparenzregister Projekt sind es die Unternehmen und Personen, +die als Vermittler fungieren und zentrale Rollen in Bereichen einnehmen +können. Auf diese wird ein besonderes Augenmerk gelegt, da hier die +meisten Auffälligkeiten vermutet werden. + +**Closeness Centrality** hilft dabei, Cluster von Knoten zu finden, die +sehr nahe aneinander sind. Dies geschieht über einen Algorithmus, der +den kürzesten Weg zwischen den Knoten sucht und die Knoten mit einer +Punktzahl aus der Summe aller Pfade versieht. Knoten mit einer hohen +*Closeness Centrality* haben einen kurzen Weg zu allen anderen Knoten. +Diese sind sehr effizient bei der Informationsverteilung - somit sind +Akteure mit einer hohen *Closeness Centrality* in der Lage, schnell das +gesamte Netzwerk zu beeinflussen. + +Bei der Interpretation dieser Kennzahl können Informationsverteiler +bestimmt werden, jedoch haben in einem sehr verbundenen Netzwerk die +Ecken meist einen sehr ähnlichen *Closeness Centrality* Wert. Daher ist +es bei diesen Netzwerken sinnvoll, eher Informationsverteiler in den +einzelnen Clustern auszumachen. [7] + +Dieser Wert wird berechnet, indem man die Gesamtanzahl an Schritte zu +einer Ecke zählt und diesen Wert invertiert. + +Neben der *Betweenness Centrality* ist dies eine der besonderen +Kennzahlen, da hiermit Akteure gefunden werden, die aufgrund ihrer +möglichst geringen direkten Verbindungen gar nicht auffallen würden, +aber durch die kurzen Wege eventuell doch Beziehungen zu vielen Akteuren +besitzen. + +**Eigenvector Centrality** gewichtet, anders als bei der *Degree +Centrality*, die Nachbarn unterschiedlich. Dafür werden die Kanten des +Ausgangsknoten gemessen, aber auch die Kanten der Folgeknoten und so +weiter bis der gesamte Graph durchlaufen ist. Nicht jeder Nachbar hat +nach dieser Metrik den gleichen Wert. Dadurch werden Ecken erkannt, die +einen Einfluss durchs gesamte oder einen Großteil des Netzwerkes haben. +Die *Eigenvector Centrality* kann sowohl für gerichtete als auch +ungerichtete Graphen verwendet werden - in der Praxis zeigt sich +allerdings, dass die ungerichteten Graphen deutlich besser +funktionieren. Die Problematiken der *Eigenvector Centrality* bei +gerichteten Graphen kann mittels der *Katz Centrality* behoben werden, +welche aber in dieser Arbeit nicht weiter behandelt wird. +[6] + +Berechnet wird die Kennzahl je Knoten durch das Bilden eines +Eigenvektors und Iterieren über jede der Kanten. Wenn die Kennzahl durch +$x$ repräsentiert wird und die Kanten durch $i$, können die Mengen der +Kanten der Nachbarn durch $x$ = $\sum$ Aii Xi, bestimmt werden, wobei +Aii ein Element der Adjacency Matrix ist. Dieser Prozess muss iterativ +durchgeführt werden, womit man $x(t)$ = $A^tx(0)$ erhält. + +**PageRank Centrality** ist eine Variante der *Eigenvector Centrality*. +Bei diesem Wert wird jeder Knoten mit einer Punktzahl abhängig der +eingehenden Verbindungen ausgestattet. Die Verbindungen werden dann +abhängig vom ausgehenden Knoten gewichtet. Diese Kennzahl wird genutzt, +um bei *directed Graphs* einflussreiche Akteure auszumachen. Es war +einer der ersten Rangfolgen Algorithmen hinter der Google Search Engine +und wurde nach dem Entwickler und Gründer Larry Page benannt. [7] + +Akteure mit einem hohen *PageRank Centrality* Wert können als besonders +einflussreich über ihre direkten Verbindungen hinaus interpretiert +werden. + +#### Group-Level Metriken + +**K-Cores** ist eine Drill-Down Möglichkeit im Netz. Jeder Knoten erhält +ein k-Wert abhängig von seinem degree. Die Knoten werden dann gruppiert +und gefiltert. Werte mit einem niedrigen k-Wert werden raus genommen. +Somit bleiben nur Werte mit einem hohen k-Wert übrig und es bilden sich +semi-autonome Gruppierungen innerhalb des Netzwerks. [8] + +Der k-Wert bietet eine Möglichkeit für das Transparenzregister +verschiedene Zoom Stufen einzubauen, damit gerade bei hohen Mengen an +Daten man noch einen Überblick gewinnt. + +**Distance/ shortest path** gibt an, wie viele "hops" benötigt werden, +um von einer Ecke zur anderen zu kommen. Der kürzeste Weg gibt die Route +an, mit der man mit so wenigen "hops" wie möglich durchs Netz kommt. Die +"hops" können auch gewichtet werden, um Distanzen berechnen zu können +oder die Menge an "hops". [8] + +Dieser Wert sagt etwas zur Weite des Netzwerks aus. Im Zusammenhang mit +dem Projekt liefert diese Metrik eher unwichtigere Erkenntnisse. +Bahnbrechende Besonderheiten lassen sind im Umfeld von Unternehmen und +Personen Verflechtungen mit dem kürzesten Weg nicht herausfinden. + +**Network Diameter** ist die kürzeste Verbindung der beiden am weitesten +entferntesten Ecken. Es zeigt Einblicke über den Weg, der genommen +werden muss, um alle Ecken des Netzes zu erreichen. + +Die Aussagekraft dieser Metrik ist vergleichbar zu der des kürzesten +Weges und ist für das Transparenzregister vernachlässigbar. Diese +Metriken können bei zeitlichem Puffer als zusätzliches Feature berechnet +werden. + +**Graph density** ist das Verhältnis der Anzahl vorhandener Ecken zu +möglichen Ecken. Die Dichte des Gesamtgraphen ist 1. Bei isolierten +Knoten wäre es 0. + +Mit dieser Metriken erhält man einen Einblick über die Dichte und somit +die Stärke und Menge an Kanten im Graph - man kann so erkennen, welche +Gruppe an Unternehmen besser vernetzt sind als andere. Damit sollte +diese Kennzahl, zwar nicht als Top Priorität, aber im späteren Verlauf +des Projektes, mit eingebaut werden. + +#### Network-Level Metriken + +**Modularity** ist die Aggregation des Netzwerks in Untergruppen +abhängig der Stärke der Verbindungen. Die Untergruppen werden Module +oder *Communities* genannt. Die Modularität gibt die Stärke der +Verbindungen an. Eine hohe Modularität sagt aus, dass eine enge +Verbindung innerhalb der *Community* besteht. + +Die meisten reinen Netzwerk-Level Metriken sind generell einfacher zu +berechnen, da sie oft einen konkreten Wert darstellen und nicht pro Ecke +kalkuliert sind. Somit können sie schnell eingebaut werden. Die +Aussagekraft der Modularität steigt mit der Anzahl an Netzwerken, die +man vergleichen möchte. Für das Projekt liegt hier Potential im +Vergleich von Ländern oder Regionen, oder der Vergleich einzelner +Unternehmens-Verflechtungen. Dieses Level ist aber zum aktuellen +Zeitpunkt noch nicht im Betrachtungsraum des Projektes. + +**Connected Components** sind Untergruppen von Ecken-Paaren, welche +jeweils über Wege verbunden sind. Bei Graphen mit mehreren Connected +components gibt die Vereinigung dieser die Summe der Kanten des Graphes +wieder. + +Mit diesem Wert können zwei Akteure oder Unternehmen gefunden werden, +die mit einander verbunden sind. Auch diese Metrik ist im Vergleich zu +den Element-Level Metriken erst mal der Priorität nach nachgestellt. + +**Average Clustering Coefficient** gibt die Wahrscheinlichkeit an, dass +zwei verbundene Ecken einen Cluster bilden. + +**Average Path length** ist die durchschnittliche Anzahl an +Verbindungen, um zwei Ecken zu verbinden. + +Sowohl *Average Clustering Coefficient* als auch *Average Path length* +können dem Transparenzregister zusätzliche Analyseinformationen liefern, +sind aber wie die anderen Netzwerk-Level Kennzahlen eher in späteren +Iterationen und Funktionen einzubauen. + +## Ein Social Graph für das Transparenzregister + +In diesem Abschnitt wird der Einstieg in die Verflechtungsanalyse für +das Transparenzregister gegeben. Betrachtet wird, anhand der Ergebnisse +eines Jupyter Notebooks, wie die Metriken auf die ersten Daten des +Projektes angewendet werden können, welche Resultate sich vermuten +lassen und wie das weitere Vorgehen im Projekt sein wird. + +### Aufbau des Social Graph/ SNA und Prämissen + +Für die Umsetzung des Graphen wird die Programmiersprache Python in der +Version 3.11 mit der freien Bibliothek NetworkX genutzt. NetworkX ist +ein Framework zur Erstellung von Graphen und Netzwerken mit Python +Datenstrukturen. Es können Graphen, Digraphen und Multigraphen damit +erstellt werden. Des Weiteren kann eine NetworkX Struktur auch in +Matplotlib oder PyVis visualisiert werden. Zu den Feinheiten der +Visualisierung wird mehr in der Hausarbeit \"Datenvisualisierung\" +berichtet. + +Da zum Entstehungszeitpunkt dieser Arbeit das Projekt noch nicht +vollständig mit Daten versorgt ist, wird an dieser Stelle mit +Mockup-Daten ein Graph erzeugt und gegen Ende dieser Arbeit eine +Vorschau mit den ersten Daten in einem Netzwerk gezeigt. + +Für die Erstellung der Daten wird mit der Python Bibliothek Pandas aus +einer Excel Datei Mockup-Daten zu verschiedenen Automobilherstellern +geladen. + +``` {.python language="Python" breaklines="true"} +# import pandas +import pandas as pd + +# create dataframe based on the sample data +df_nodes = pd.read_csv('companies.csv', sep = ';') + +# define shape based on the type +node_shape = {'Company': 'dot', 'Person': 'triangle'} +df_nodes['shape'] = df_nodes['type'].map(node_shape) + +# define color based on branche +node_color = { + 'Automobilhersteller': ' #729b79ff', + 'Automobilzulieferer': '#475b63ff', + 'Branche 3': '#f3e8eeff', + 'Branche 4': '#bacdb0ff', + 'Branche 5': '#2e2c2fff', +} +df_nodes['color'] = df_nodes['branche'].map(node_color) + +# add information column that can be used for +the mouse over in the graph +df_nodes = df_nodes.fillna('') +df_nodes['title'] = df_nodes['label'] + '\n' + +df_nodes['branche'] + +# show first five entries of the dataframe +print(df_nodes.head()) +``` + +Als Ergebnis erhält man ein Dataframe mit den verschiedenen +Automobilherstellern. + +| **ID** | **Name** | **Typ** | +|--------|---------------------------|---------| +| 1 | Porsche Automobil Holding | Company | +| 2 | Volkswagen AG | Company | +| 3 | Volkswagen | Company | + +*Tabelle 1: Tabelle der Automobilhersteller.* + + +Neben den Daten zu den Firmen wird noch eine zweite Tabelle +\"relations\" eingelesen, welche die Beziehungen zwischen den Akteuren +beinhaltet. Aus den beiden Tabellen wird ein harmonisiertes Dataframe +erstellt, aus welchem mit der Bibliothek NetworkX ein Graph erstellt +wird. Dafür wird die Methode from_pandas_edgelist genutzt - diese +erstellt aus einem Dataframe einen Graphen. + +``` {.python language="Python" breaklines="true"} +# import networkx +import networkx as nx + +# create edges from dataframe +graph = nx.from_pandas_edgelist(df_edges, source="from", +target="to", edge_attr="label") +``` + +Anschließend wird der erzeugte Graph mit PyVis visualisiert. + +``` {.python language="Python" breaklines="true"} +# visualize using pyvis +from pyvis.network import Network + +net = Network( +directed=False, neighborhood_highlight=True, +bgcolor="white", font_color="black") + +# pass networkx graph to pyvis +net.from_nx(graph) + +# set edge options +net.inherit_edge_colors(False) +net.set_edge_smooth("dynamic") + +adj_list = net.get_adj_list() + +# calculate and update size of the nodes +depending on their number of edges +for node_id, neighbors in adj_list.items(): + df["edges"] = measure_vector.values() + +size = 10 # len(neighbors)*5 + +next( +(node.update({"size": size}) for node in net.nodes if node["id"] == node_id), + None,) + +# set the node distance and spring lenght using repulsion +net.repulsion(node_distance=150, spring_length=50) + +# activate physics buttons to further explore the available solvers: +# barnesHut, forceAtlas2Based, repulsion, hierarchicalRepulsion +net.show_buttons(filter_=["physics"]) + +# save graph as HTML +net.save_graph("./metrics/test.html") +``` + +Das Resultat ist ein vollständiger Graph, welcher als HTML gespeichert +ist. Öffnet man den Graphen in einem Browser, kann man die einzelnen +Knoten auswählen und bekommt ein Highlighting der verknüpften Knoten. +Des Weiteren können Einstellungen an der Physik vorgenommen werden, um +die Ansicht des Graphen zu verändern, beispielsweise die Knoten +auseinander zu ziehen. + +![Abbildung eines Graphens mit Mockdaten](abbildungen/Graph.PNG) + +### Anwendung der Social Network Analysis (SNA) + +Der Graph kann nun mit den verschiedenen Metriken bestückt werden, +sodass die SNA vollzogen werden kann. + +#### Erstellen eines Graphen mit der Element-Level Metriken + +Über das Framework NetworkX besteht die Möglichkeit, die Metriken direkt +berechnen zu lassen. Dazu wird die Methode *eigenvector_centrality* auf +den Graphen angewandt. Als Rückgabewert gibt es ein Dictionary mit den +Eigenvector Werten. Das Dictionary muss mit einem Faktor multipliziert +werden, um einen sichtlichen Unterschied bei den Größen der Ecken zu +erhalten. Über die adjacency list des Netzwerks kann auf die Ecken des +Netzwerks zugegriffen werden. Diese wird zu Nutze gemacht, um in einer +for-Schleife die Größe der Ecken neu zu setzen. Der Quellcodes sieht wie +folgt aus: + +``` {.python language="Python" breaklines="true"} +adj_list = net.get_adj_list() + +measure_vector = {} + +if measure_type == "eigenvector": + measure_vector = nx.eigenvector_centrality(graph) + df["eigenvector"] = measure_vector.values() +if measure_type == "degree": + measure_vector = nx.degree_centrality(graph) + df["degree"] = measure_vector.values() +if measure_type == "betweeness": + measure_vector = nx.betweenness_centrality(graph) + df["betweeness"] = measure_vector.values() +if measure_type == "closeness": + measure_vector = nx.closeness_centrality(graph) + df["closeness"] = measure_vector.values() + +# calculate and update size of the nodes depending on their number of edges +for node_id, neighbors in adj_list.items(): +# df["edges"] = measure_vector.values() + +if measure_type == "edges": + size = 10 # len(neighbors)*5 +else: + size = measure_vector[node_id] * 50 + next( + ( + node.update({"size": size}) + for node in net.nodes if node["id"] == node_id), + None, + ) +``` + +Selbiges wird mit den Kennzahlen *degree_centrality, +betweennes_centrality* und *closeness_centrality* durchgeführt. Über die +*save_graph* Methode kann das Netzwerk dank des Pyvis Frameworks als +HTML gespeichert und das fertige Netz im Browser betrachtet werden. + +![Netzwerk mit der Metrik eigenvector centrality.](abbildungen/Eigenvector.PNG) + +Anhand der Veränderung des Netzwerks kann man sehen, wie die +Auswirkungen der Kennzahlen sind. Der Eigenvector misst, wie viele +Verbindungen von einem Knoten ausgehen und wie viele vom nächsten +Nachbarn aus weitergehen, bis das Netz durchdrungen ist. Daher sticht +vor allem die Porsche AG in diesem Beispiel deutlich hervor, da diese +viele direkt Verbindungen hat und mit dem Audi Knoten verbunden ist, der +wiederum die zweit meisten Verknüpfungen besitzt. + +![Netzwerk mit der Metrik degree centrality.](abbildungen/Degree.PNG) + +Die *Degree Centrality* zeigt hingegen ein etwas anderes Bild. Hier sind +die Hauptakteure noch einmal deutlich größer im Verhältnis zu den +Blättern des Netzes. Es wurden hierfür nur die direkten Verbindungen der +Knoten gezählt, deswegen ist "Hella" auch genau gleich groß wie "Seat" +und "Skoda Auto", da alle nur eine direkte Verbindung besitzen. Beim +vorherigen Graphen war "Seat" größer, da es mit einem einflussreichen +Knoten verbunden war und Hella nicht. + +![Netzwerk mit der Metrik betweenness centrality.](abbildungen/Betweenness.PNG) + +Im dritten Graphen mit der *betweenness centrality* sieht man, dass die +Blätter keinen Knoten mehr haben, da dieser nicht als \"Brücke\" +fungiert. In einem sehr großen Netzwerk könnte man solche Knoten +wegfallen lassen, um ein genaueren Überblick der wichtigen Akteure zu +erhalten. + +![Netzwerk mit der Metrik closeness centrality.](abbildungen/Closeness.PNG) + +Die letzte Metrik der Element-Level Metriken zeigt ein eher homogenes +Bild. Die Knoten sind generell größer, was daran liegt, dass es hier +keine unterschiedlichen Subnetze gibt. + +#### Berechnung, Aufbau und Interpretationsmöglichkeiten der Group-Level Metriken + +Für die Group-Level Metriken wurden zwei Metriken an den Testdaten +ausprobiert: + +- Distance/shortest path + +- Network Diameter + +Da in den Testdaten keine klare Gruppierung festgestellt wurde, können +die Kennzahlen lediglich auf das gesamte Netzwerk angewendet werden. Die +ermittelten Ergebnisse zeigen, dass die Distanz einen Wert von 3 und der +sogenannte *Network Diameter* einen Wert von 4 aufweisen. Dies bedeutet, +dass die kürzeste Verbindung im Netzwerk lediglich 3 Verbindungen +erfordert, während die längste Verbindung maximal 4 Verbindungen +benötigt. Diese Werte deuten darauf hin, dass das Netzwerk insgesamt +recht effizient in Bezug auf die Verbindungen zwischen seinen +Knotenpunkten ist, wobei die meisten Verbindungen relativ kurz sind und +es nur wenige längere Verbindungen gibt, was bei einem so kleinen +Netzwerk nicht verwunderlich ist. + +#### Berechnung, Aufbau und Interpretationsmöglichkeiten der Network-Level Metriken + +In der Analyse der Netzwerkkennzahlen wurden ausschließlich die +Testdaten verwendet, um die durchschnittliche Pfadlänge zu berechnen. +Diese beträgt 2,3 Verbindungen. Dies bedeutet, dass es im Schnitt nur +etwa 2,3 Schritte braucht, um von einem Punkt zum anderen im Netzwerk zu +gelangen. Eine niedrige durchschnittliche Pfadlänge zeigt an, dass das +Netzwerk effizient und gut miteinander verbunden ist. + +### Weitere Analysen + +Neben den bereits besprochenen Analysemetriken aus der Graphentheorie +werden für das Transparenzregister weitere Elemente benötigt, um mehr +Informationen aus den Daten zu gewinnen. Dazu wird ein Ausgangsgraph +erstellt, welcher alle Akteure als uneingefärbte Knoten darstellt und +diese miteinander nach den Beziehungen aus der Datenbank über Kanten +verbindet. Die Beziehung in der Datenbank sind gerichtete Werte zwischen +zwei Akteuren. Es können mehrere Beziehungen in dieselbe Richtung gehen. +Beispielsweise kann zwischen Unternehmen A und Unternehmen B die +Verbindung ist_Teil_von, teilen_x_Mitarbeiter und beauftragt bestehen. +Damit diese in einem *Social Network* lesbar dargestellt werden können, +müssen die Kanten ungerichtet und unterschiedlicher Länge sein. Dafür +werden die Beziehungen ähnlich wie bei der *Degree Centrallity* +gemittelt und gewichtet. Die Länge der Kanten ist disproportional +abhängig von der Gewichtung und liegt zwischen 1 und 10. Eine hohe +Gewichtung resultiert also in einer Kantenlänge nahe 1, eine niedrige +nahe 10. Damit wird eine Federkraft generiert, die Knoten mit starken +Verbindungen anzieht. Des Weiteren ist eine Mindestdistanz zwischen +Knoten festgelegt, damit sich beim Generieren des Netzes keine Knoten +überlappen. Somit ergibt sich ein Ausgangsgraph, welcher über die +folgenden Anpassungen verändert werden kann, um weitere Erkenntnisse zu +gewinnen. + +Die erste Option besteht im Verändern der Größe der einzelnen Knoten. +Analog zur Größenveränderung bei den Metriken aus der Graphentheorie ist +es bei diesem Graphen machbar, eine der folgenden Metriken aus dem +Transparenzregister Projekt als Ausgangspunkt für den Radius der Knoten +zu wählen und/oder zu filtern: + +EBIT, Umsatz, Aktienkurs, Mitarbeiteranzahl und die Wachstumsrate + +Personen werden bei dieser Betrachtung weiterhin mit der Einheitsgröße 1 +dargestellt oder raus gefiltert. Der Filter kann mit einem Schwellenwert +versehen werden, um nur Unternehmen in bestimmter Größenordnung zu +vergleichen. Damit wird dem Betrachter ersichtlich, welche Unternehmen +beispielsweise einen hohen Umsatz erzielen im Vergleich zum Rest. + +Neben dieser Funktionalität können die Knoten nach den folgenden +Kategorien eingefärbt oder gefiltert werden: + +Branche, Heimatland, Mutterkonzern, Wachstumsrate, und +Positiver/Negativer Berichtserstattung + +In Kombination mit dem vorherigen Ansatz sind Analysen hinsichtlich der +Unternehmen mit den größten Umsätze nach Ländern denkbar. + +Abgesehen von diesen eher visuellen Betrachtungen besteht die letzte +Konfiguration im Verändern der Kanten. Darüber hinaus kann das Netzwerk +nach den einzelnen Beziehungstypen aufgebaut werden. + +Weiterhin ist eine Variante auswählbar, bei der die Formel der +Federspannung über eine Gewichtung der Akteure erweitert wird. +Verbindungen zu Wirtschaftsprüfern werden zum Beispiel geringer bewertet +als geteilte Vorstandspersonen. Somit wird der Fokus auf +Unternehmensgruppen gelegt, bei denen die priorisierten Merkmale +deutlich herausstechen. + +Die letzte Selektion ermöglicht es, Verbindungen zur selben Holding oder +Mutterkonzern heraus zu nehmen. Nach diesem Filter sind nur noch externe +Verbindungen ersichtlich und der Graph wird deutlich übersichtlicher. Es +wird einfacher erkennbar, welche Unternehmen mit welchen Akteuren +zusammenarbeiten. + +Diese eigenen Analyseoptionen können nach Belieben miteinander +kombiniert werden, um verschiedene Sichtweise auf des Netzgefüge zu +erhalten. + +### Perspektive auf einen Graphen mit Unternehmens und Personen Daten + +Gegen ende dieser Arbeit ist hier noch ein Graph mit einem Auszug an +realen Daten aus dem Transparenzregister zu sehen. Bereits ohne die +Verwendung von Metriken sind Gruppenbildungen deutlich zu erkennen. +Insgesamt wurden 1000 Verflechtungen hier dargestellt. Als Knoten +dienten Personen und Firmen. Die Unternehmen wurden grün dargestellt, +sind aber aufgrund der Größe eher schlecht von den Personen mit blauen +Punkten zu unterscheiden. + +![Graph mit Unternehmens- und Personendaten](abbildungen/Transparenzregister_Graph.PNG) + +### Handlungsempfehlung + +Für das Projekt Transparenzregister leitet sich aus dieser Arbeit +folgende Empfehlung für die SNA ab: + +Für die Umsetzung der SNA eignet sich die Bibliothek NetworkX sehr gut, +da sie anhand eines Pandas Dataframe bereits ein gutes Netzwerk aufbauen +kann. Des Weiteren können eine Vielzahl an Metriken effizient mit dem +Netzwerk berechnet werden und benötigen keine extra Implementierung von +Algorithmen. Zusätzlich wird empfohlen, das Framework PyVis zur +Visualisierung zu nutzen, da es das Netzwerk gut aufbereitet und zur +Laufzeit Anpassungen an der Grafik zulässt. + +Bezogen auf die Auswahl der Metriken wird auf den Nutzen vor allem von +Element-Level Metriken verwiesen. Spezifisch sollten folgende Metriken +betrachtet werden: + +- Degree Centrality + +- Betweenes Centrality + +- Closeness Centrality + +- Eigenvector Centrality + +Für die Group-Level Metriken werden folgende Metriken angeraten: + +- Distance/shortest path + +- Network Diameter + +Zuletzt werden für die Netzwerk-Level Metriken die nachstehenden +Metriken befürwortet: + +- Average Path length + +- Modularity + +Natürlich können auch die anderen Metriken genutzt werden. Die hier +vorgeschlagene Auswahl ergeben nach der Einschätzung und Erläuterungen +dieser Arbeit den größtmöglichen Nutzen für das Projekt und sollten aus +den genannten Gründen priorisiert werden. + +## Zusammenfassung + +In diesem Abschnitt wird die Arbeit rückwirkend kritisch betrachtet, +zusammengefasst und ein Fazit gezogen. Zum Schluss wird ein kleiner +Ausblick auf die nächsten Fragestellungen gegeben, die es im genannten +Projekt zu beantworten gilt. + +### Kritische Reflexion + +Zielsetzung war es, im Rahmen dieser Arbeit sich mit der +Verflechtungsanalyse auseinanderzusetzen. Die grundlegenden Metriken und +Vorgehensweisen wurden aufgezeigt, eine intensivere Betrachtung der +Metriken und Anwendung auf größere Daten sollte in einer erneuten +Betrachtung als Ziel gesetzt werden. Mit einem Ausschnitt an realen +Daten sind bessere und deutlichere Einschätzung der Metriken und Treffen +von Aussagen denkbar. Leider bestand der Zugriff auf echte Daten erst +gegen Ende der Bearbeitungszeit und konnte deshalb nicht für das Testen +der Analyse genutzt werden. + +### Fazit + +In der vorliegenden Untersuchung wird die Bedeutung und Anwendung einer +Verflechtungsanalyse verdeutlicht. Die Verflechtungsanalyse findet in +Rahmen eines Transparenzregister Projektes für +Unternehmensverflechtungen statt und soll im späteren Verlauf des +Projektes angewendet werden. Diese Arbeit dient als Grundlage für das +Projekt. Deshalb wurde aufgezeigt, auf welcher Grundlage ein Netzwerk an +Verflechtungen basiert und wie es mithilfe von NetworkX und PyVis +aufgebaut werden kann. + +Zusätzliche wurde ein Einblick in die Social Network Analyse gegeben und +eine größere Anzahl an Metriken vorgestellt. Die Metriken wurden anhand +des Projektes bewertet und eingeordnet, sodass mittels dieser +Einschätzung eine Auswahl an Metriken stattfinden kann. + +Im Hauptteil des Werks wurde dann auf die konkrete Umsetzung mit Python +eingegangen. Es wurde gezeigt, wie ein Netzwerk mit Beispieldaten +aufgebaut wird und wie dazu die benötigten Metriken angewandt werden. +Ein weiterer Aspekt bestand in der Veranschaulichung, wie die Metriken +in das Netz eingebaut werden können, um eine visuelle Analyse +durchzuführen. + +Neben den Metriken wurde auch auf weitere Analysemöglichkeiten durch +Farbgestaltung oder Größenveränderung der Knoten eingegangen. Zu guter +Letzt gab es einen Ausblick auf einen Prototypen Graph mit realen +Unternehmensdaten, aber ohne weitere Analysen. + +### Ausblick + +Der nächste logische Schritt besteht in der konkreten Ausarbeitung der +Verflechtungsanalyse mit realen Daten. Dort gilt es zu überprüfen, +welche Erkenntnisse mithilfe der SNA auf den Daten gewonnen werden +können. Liefern die vorgeschlagenen Metriken die zu erwartenden +Resultate? Sind alle Metriken überhaupt mit den Daten anwendbar? Diese +Fragestellungen werden im Rahmen des Projektes angegangen. + +### Literaturverzeichnis + +- **[1]** S. Iwanowski und R. Lang, „Graphentheorie,“ ger, in Diskrete Mathematik mit +Grundlagen, Wiesbaden: Springer Fachmedien Wiesbaden, 2020, S. 257–320, isbn: +3658327596. + +- **[2]** P. Hartmann, „Graphentheorie,“ ger, in Mathematik für Informatiker, Wiesbaden: +Springer Fachmedien Wiesbaden, 2020, S. 269–300, isbn: 9783658265236. +- **[3]** I. Pitas, Graph-Based Social Media Analysis. CRC Press, 2016, isbn: 9780429162602. + +- **[4]** X. Fu, Social Network Analysis. CRC Press, 2017, isbn: 9781315369594. + +- **[5]** E. Yüksel, https://medium.com/@emreeyukseel/a-brief-introduction-to-social-network-analysis-2d13427f5189. + +- **[6]** M. Newmans, Networks An introduction. Oxford University Press Inc., 2010, isbn: +9780199206650. + +- **[7]** A. Disney,https://cambridge-intelligence.com/keylines-faqs-social-network-analysis/. + +- **[8]** C. Intelligence, https://cambridge-intelligence.com/social-network-analysis/. \ No newline at end of file diff --git a/documentations/index.rst b/documentations/index.rst index a33e024..220dd78 100644 --- a/documentations/index.rst +++ b/documentations/index.rst @@ -21,6 +21,7 @@ Diese sind, um Industriestandards zu entsprechen, auf Englisch gehalten. Ergebnisse/Zwischenbericht_und_Praesentation/PhHo/dev-ops Ergebnisse/Zwischenbericht_und_Praesentation/TrNo/Ausarbeitung.md seminararbeiten/Datenspeicherung/00_Datenspeicherung + Ergebnisse/Zwischenbericht_und_Praesentation/TiRo/verflechtungsanalyse.md .. toctree:: @@ -28,12 +29,15 @@ Diese sind, um Industriestandards zu entsprechen, auf Englisch gehalten. :caption: Abschlussberichte :numbered: + Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S2.md + Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S3.md Ergebnisse/Abschlussbericht_und_Praesentation/PhHo/05-DEV-OPS Ergebnisse/Abschlussbericht_und_Praesentation/TrNo/S4-2.md Ergebnisse/Abschlussbericht_und_Praesentation/TrNo/S4-3-1.md Ergebnisse/Abschlussbericht_und_Praesentation/PhHo/4-4-2-database-generator Ergebnisse/Abschlussbericht_und_Praesentation/PhHo/04-data-visualisation-container.md + Ergebnisse/Abschlussbericht_und_Praesentation/TiRo/S4-5-2.md .. toctree:: :glob: diff --git a/poetry.lock b/poetry.lock index ba4fc00..e3b114d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "accelerate" @@ -1641,22 +1641,23 @@ files = [ [[package]] name = "dnspython" -version = "2.4.2" +version = "2.5.0" description = "DNS toolkit" optional = false -python-versions = ">=3.8,<4.0" +python-versions = ">=3.8" files = [ - {file = "dnspython-2.4.2-py3-none-any.whl", hash = "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8"}, - {file = "dnspython-2.4.2.tar.gz", hash = "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984"}, + {file = "dnspython-2.5.0-py3-none-any.whl", hash = "sha256:6facdf76b73c742ccf2d07add296f178e629da60be23ce4b0a9c927b1e02c3a6"}, + {file = "dnspython-2.5.0.tar.gz", hash = "sha256:a0034815a59ba9ae888946be7ccca8f7c157b286f8455b379c692efb51022a15"}, ] [package.extras] -dnssec = ["cryptography (>=2.6,<42.0)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.24.1)"] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=5.0.3)", "mypy (>=1.0.1)", "pylint (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0.0)", "sphinx (>=7.0.0)", "twine (>=4.0.0)", "wheel (>=0.41.0)"] +dnssec = ["cryptography (>=41)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.25.1)"] doq = ["aioquic (>=0.9.20)"] -idna = ["idna (>=2.1,<4.0)"] -trio = ["trio (>=0.14,<0.23)"] -wmi = ["wmi (>=1.5.1,<2.0.0)"] +idna = ["idna (>=2.1)"] +trio = ["trio (>=0.14)"] +wmi = ["wmi (>=1.5.1)"] [[package]] name = "docutils" @@ -2427,13 +2428,13 @@ files = [ [[package]] name = "jsonschema" -version = "4.21.0" +version = "4.21.1" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.21.0-py3-none-any.whl", hash = "sha256:70a09719d375c0a2874571b363c8a24be7df8071b80c9aa76bc4551e7297c63c"}, - {file = "jsonschema-4.21.0.tar.gz", hash = "sha256:3ba18e27f7491ea4a1b22edce00fb820eec968d397feb3f9cb61d5894bb38167"}, + {file = "jsonschema-4.21.1-py3-none-any.whl", hash = "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f"}, + {file = "jsonschema-4.21.1.tar.gz", hash = "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5"}, ] [package.dependencies] @@ -2939,6 +2940,7 @@ files = [ {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e8f9f93a23634cfafbad6e46ad7d09e0f4a25a2400e4a64b1b7b7c0fbaa06d9d"}, {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3f3f00a9061605725df1816f5713d10cd94636347ed651abdbc75828df302b20"}, {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:953dd5481bd6252bd480d6ec431f61d7d87fdcbbb71b0d2bdcfc6ae00bb6fb10"}, + {file = "lxml-4.9.4-cp312-cp312-win32.whl", hash = "sha256:266f655d1baff9c47b52f529b5f6bec33f66042f65f7c56adde3fcf2ed62ae8b"}, {file = "lxml-4.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:f1faee2a831fe249e1bae9cbc68d3cd8a30f7e37851deee4d7962b17c410dd56"}, {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:23d891e5bdc12e2e506e7d225d6aa929e0a0368c9916c1fddefab88166e98b20"}, {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e96a1788f24d03e8d61679f9881a883ecdf9c445a38f9ae3f3f193ab6c591c66"}, @@ -3052,71 +3054,71 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.4" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, + {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, ] [[package]] @@ -3794,13 +3796,13 @@ attrs = ">=19.2.0" [[package]] name = "overrides" -version = "7.4.0" +version = "7.6.0" description = "A decorator to automatically detect mismatch when overriding a method." optional = false python-versions = ">=3.6" files = [ - {file = "overrides-7.4.0-py3-none-any.whl", hash = "sha256:3ad24583f86d6d7a49049695efe9933e67ba62f0c7625d53c59fa832ce4b8b7d"}, - {file = "overrides-7.4.0.tar.gz", hash = "sha256:9502a3cca51f4fac40b5feca985b6703a5c1f6ad815588a7ca9e285b9dca6757"}, + {file = "overrides-7.6.0-py3-none-any.whl", hash = "sha256:c36e6635519ea9c5b043b65c36d4b886aee8bd45b7d4681d2a6df0898df4b654"}, + {file = "overrides-7.6.0.tar.gz", hash = "sha256:01e15bbbf15b766f0675c275baa1878bd1c7dc9bc7b9ee13e677cdba93dc1bd9"}, ] [[package]] @@ -3913,6 +3915,20 @@ files = [ numpy = {version = ">=1.26.0", markers = "python_version < \"3.13\""} types-pytz = ">=2022.1.1" +[[package]] +name = "pandoc" +version = "2.3" +description = "Pandoc Documents for Python" +optional = false +python-versions = "*" +files = [ + {file = "pandoc-2.3.tar.gz", hash = "sha256:e772c2c6d871146894579828dbaf1efd538eb64fc7e71d4a6b3a11a18baef90d"}, +] + +[package.dependencies] +plumbum = "*" +ply = "*" + [[package]] name = "pandocfilters" version = "1.5.1" @@ -4123,13 +4139,13 @@ test = ["coverage[toml] (>=7.0,!=7.3.3,<8.0)", "pretend", "pytest", "pytest-cov" [[package]] name = "pip-licenses" -version = "4.3.3" +version = "4.3.4" description = "Dump the software license list of Python packages installed with pip." optional = false python-versions = "~=3.8" files = [ - {file = "pip-licenses-4.3.3.tar.gz", hash = "sha256:d14447094135eb5e43e4d9e1e3bcdb17a05751a9199df2d07f043a542c241c7a"}, - {file = "pip_licenses-4.3.3-py3-none-any.whl", hash = "sha256:1b697cace3149d7d380307bb1f1e0505f0db98f25fada64d32b7e6240f37f72c"}, + {file = "pip-licenses-4.3.4.tar.gz", hash = "sha256:9c6c9c3252b976d08735bdffb0eb4c5eaa50dfd46f5e075532c0248ffe94fed1"}, + {file = "pip_licenses-4.3.4-py3-none-any.whl", hash = "sha256:85706ec30781076eb611fed3934f27a1f18437d3211f747567cd3c4e943fce1b"}, ] [package.dependencies] @@ -4202,6 +4218,36 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "plumbum" +version = "1.8.2" +description = "Plumbum: shell combinators library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "plumbum-1.8.2-py3-none-any.whl", hash = "sha256:3ad9e5f56c6ec98f6f7988f7ea8b52159662ea9e915868d369dbccbfca0e367e"}, + {file = "plumbum-1.8.2.tar.gz", hash = "sha256:9e6dc032f4af952665f32f3206567bc23b7858b1413611afe603a3f8ad9bfd75"}, +] + +[package.dependencies] +pywin32 = {version = "*", markers = "platform_system == \"Windows\" and platform_python_implementation != \"PyPy\""} + +[package.extras] +dev = ["paramiko", "psutil", "pytest (>=6.0)", "pytest-cov", "pytest-mock", "pytest-timeout"] +docs = ["sphinx (>=4.0.0)", "sphinx-rtd-theme (>=1.0.0)"] +ssh = ["paramiko"] + +[[package]] +name = "ply" +version = "3.11" +description = "Python Lex & Yacc" +optional = false +python-versions = "*" +files = [ + {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, + {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, +] + [[package]] name = "pockets" version = "0.9.1" @@ -4385,27 +4431,27 @@ files = [ [[package]] name = "psutil" -version = "5.9.7" +version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "psutil-5.9.7-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0bd41bf2d1463dfa535942b2a8f0e958acf6607ac0be52265ab31f7923bcd5e6"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5794944462509e49d4d458f4dbfb92c47539e7d8d15c796f141f474010084056"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:fe361f743cb3389b8efda21980d93eb55c1f1e3898269bc9a2a1d0bb7b1f6508"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:e469990e28f1ad738f65a42dcfc17adaed9d0f325d55047593cb9033a0ab63df"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:3c4747a3e2ead1589e647e64aad601981f01b68f9398ddf94d01e3dc0d1e57c7"}, - {file = "psutil-5.9.7-cp27-none-win32.whl", hash = "sha256:1d4bc4a0148fdd7fd8f38e0498639ae128e64538faa507df25a20f8f7fb2341c"}, - {file = "psutil-5.9.7-cp27-none-win_amd64.whl", hash = "sha256:4c03362e280d06bbbfcd52f29acd79c733e0af33d707c54255d21029b8b32ba6"}, - {file = "psutil-5.9.7-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ea36cc62e69a13ec52b2f625c27527f6e4479bca2b340b7a452af55b34fcbe2e"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1132704b876e58d277168cd729d64750633d5ff0183acf5b3c986b8466cd0284"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8b7f07948f1304497ce4f4684881250cd859b16d06a1dc4d7941eeb6233bfe"}, - {file = "psutil-5.9.7-cp36-cp36m-win32.whl", hash = "sha256:b27f8fdb190c8c03914f908a4555159327d7481dac2f01008d483137ef3311a9"}, - {file = "psutil-5.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:44969859757f4d8f2a9bd5b76eba8c3099a2c8cf3992ff62144061e39ba8568e"}, - {file = "psutil-5.9.7-cp37-abi3-win32.whl", hash = "sha256:c727ca5a9b2dd5193b8644b9f0c883d54f1248310023b5ad3e92036c5e2ada68"}, - {file = "psutil-5.9.7-cp37-abi3-win_amd64.whl", hash = "sha256:f37f87e4d73b79e6c5e749440c3113b81d1ee7d26f21c19c47371ddea834f414"}, - {file = "psutil-5.9.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:032f4f2c909818c86cea4fe2cc407f1c0f0cde8e6c6d702b28b8ce0c0d143340"}, - {file = "psutil-5.9.7.tar.gz", hash = "sha256:3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c"}, + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, ] [package.extras] @@ -5119,7 +5165,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -5127,15 +5172,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -5152,7 +5190,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -5160,7 +5197,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -5962,45 +5998,45 @@ tests = ["black (>=23.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.3)", "numpydoc ( [[package]] name = "scipy" -version = "1.11.4" +version = "1.12.0" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "scipy-1.11.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc9a714581f561af0848e6b69947fda0614915f072dfd14142ed1bfe1b806710"}, - {file = "scipy-1.11.4-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:cf00bd2b1b0211888d4dc75656c0412213a8b25e80d73898083f402b50f47e41"}, - {file = "scipy-1.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9999c008ccf00e8fbcce1236f85ade5c569d13144f77a1946bef8863e8f6eb4"}, - {file = "scipy-1.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:933baf588daa8dc9a92c20a0be32f56d43faf3d1a60ab11b3f08c356430f6e56"}, - {file = "scipy-1.11.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8fce70f39076a5aa62e92e69a7f62349f9574d8405c0a5de6ed3ef72de07f446"}, - {file = "scipy-1.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:6550466fbeec7453d7465e74d4f4b19f905642c89a7525571ee91dd7adabb5a3"}, - {file = "scipy-1.11.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f313b39a7e94f296025e3cffc2c567618174c0b1dde173960cf23808f9fae4be"}, - {file = "scipy-1.11.4-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1b7c3dca977f30a739e0409fb001056484661cb2541a01aba0bb0029f7b68db8"}, - {file = "scipy-1.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00150c5eae7b610c32589dda259eacc7c4f1665aedf25d921907f4d08a951b1c"}, - {file = "scipy-1.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:530f9ad26440e85766509dbf78edcfe13ffd0ab7fec2560ee5c36ff74d6269ff"}, - {file = "scipy-1.11.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5e347b14fe01003d3b78e196e84bd3f48ffe4c8a7b8a1afbcb8f5505cb710993"}, - {file = "scipy-1.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:acf8ed278cc03f5aff035e69cb511741e0418681d25fbbb86ca65429c4f4d9cd"}, - {file = "scipy-1.11.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:028eccd22e654b3ea01ee63705681ee79933652b2d8f873e7949898dda6d11b6"}, - {file = "scipy-1.11.4-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2c6ff6ef9cc27f9b3db93a6f8b38f97387e6e0591600369a297a50a8e96e835d"}, - {file = "scipy-1.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b030c6674b9230d37c5c60ab456e2cf12f6784596d15ce8da9365e70896effc4"}, - {file = "scipy-1.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad669df80528aeca5f557712102538f4f37e503f0c5b9541655016dd0932ca79"}, - {file = "scipy-1.11.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce7fff2e23ab2cc81ff452a9444c215c28e6305f396b2ba88343a567feec9660"}, - {file = "scipy-1.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:36750b7733d960d7994888f0d148d31ea3017ac15eef664194b4ef68d36a4a97"}, - {file = "scipy-1.11.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e619aba2df228a9b34718efb023966da781e89dd3d21637b27f2e54db0410d7"}, - {file = "scipy-1.11.4-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:f3cd9e7b3c2c1ec26364856f9fbe78695fe631150f94cd1c22228456404cf1ec"}, - {file = "scipy-1.11.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d10e45a6c50211fe256da61a11c34927c68f277e03138777bdebedd933712fea"}, - {file = "scipy-1.11.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91af76a68eeae0064887a48e25c4e616fa519fa0d38602eda7e0f97d65d57937"}, - {file = "scipy-1.11.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6df1468153a31cf55ed5ed39647279beb9cfb5d3f84369453b49e4b8502394fd"}, - {file = "scipy-1.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:ee410e6de8f88fd5cf6eadd73c135020bfbbbdfcd0f6162c36a7638a1ea8cc65"}, - {file = "scipy-1.11.4.tar.gz", hash = "sha256:90a2b78e7f5733b9de748f589f09225013685f9b218275257f8a8168ededaeaa"}, + {file = "scipy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78e4402e140879387187f7f25d91cc592b3501a2e51dfb320f48dfb73565f10b"}, + {file = "scipy-1.12.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5f00ebaf8de24d14b8449981a2842d404152774c1a1d880c901bf454cb8e2a1"}, + {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e53958531a7c695ff66c2e7bb7b79560ffdc562e2051644c5576c39ff8efb563"}, + {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e32847e08da8d895ce09d108a494d9eb78974cf6de23063f93306a3e419960c"}, + {file = "scipy-1.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c1020cad92772bf44b8e4cdabc1df5d87376cb219742549ef69fc9fd86282dd"}, + {file = "scipy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:75ea2a144096b5e39402e2ff53a36fecfd3b960d786b7efd3c180e29c39e53f2"}, + {file = "scipy-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:408c68423f9de16cb9e602528be4ce0d6312b05001f3de61fe9ec8b1263cad08"}, + {file = "scipy-1.12.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5adfad5dbf0163397beb4aca679187d24aec085343755fcdbdeb32b3679f254c"}, + {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3003652496f6e7c387b1cf63f4bb720951cfa18907e998ea551e6de51a04467"}, + {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8066bce124ee5531d12a74b617d9ac0ea59245246410e19bca549656d9a40a"}, + {file = "scipy-1.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8bee4993817e204d761dba10dbab0774ba5a8612e57e81319ea04d84945375ba"}, + {file = "scipy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a24024d45ce9a675c1fb8494e8e5244efea1c7a09c60beb1eeb80373d0fecc70"}, + {file = "scipy-1.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e7e76cc48638228212c747ada851ef355c2bb5e7f939e10952bc504c11f4e372"}, + {file = "scipy-1.12.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f7ce148dffcd64ade37b2df9315541f9adad6efcaa86866ee7dd5db0c8f041c3"}, + {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c39f92041f490422924dfdb782527a4abddf4707616e07b021de33467f917bc"}, + {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7ebda398f86e56178c2fa94cad15bf457a218a54a35c2a7b4490b9f9cb2676c"}, + {file = "scipy-1.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:95e5c750d55cf518c398a8240571b0e0782c2d5a703250872f36eaf737751338"}, + {file = "scipy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e646d8571804a304e1da01040d21577685ce8e2db08ac58e543eaca063453e1c"}, + {file = "scipy-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:913d6e7956c3a671de3b05ccb66b11bc293f56bfdef040583a7221d9e22a2e35"}, + {file = "scipy-1.12.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba1b0c7256ad75401c73e4b3cf09d1f176e9bd4248f0d3112170fb2ec4db067"}, + {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:730badef9b827b368f351eacae2e82da414e13cf8bd5051b4bdfd720271a5371"}, + {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6546dc2c11a9df6926afcbdd8a3edec28566e4e785b915e849348c6dd9f3f490"}, + {file = "scipy-1.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:196ebad3a4882081f62a5bf4aeb7326aa34b110e533aab23e4374fcccb0890dc"}, + {file = "scipy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:b360f1b6b2f742781299514e99ff560d1fe9bd1bff2712894b52abe528d1fd1e"}, + {file = "scipy-1.12.0.tar.gz", hash = "sha256:4bf5abab8a36d20193c698b0f1fc282c1d083c94723902c447e5d2f1780936a3"}, ] [package.dependencies] -numpy = ">=1.21.6,<1.28.0" +numpy = ">=1.22.4,<1.29.0" [package.extras] dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] -test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "seaborn" @@ -6719,7 +6755,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"} mypy = {version = ">=0.910", optional = true, markers = "python_version >= \"3\" and extra == \"mypy\""} sqlalchemy2-stubs = {version = "*", optional = true, markers = "extra == \"mypy\""} @@ -7807,4 +7843,4 @@ web-server = ["dash", "dash-auth", "dash-bootstrap-components", "dash-daq", "net [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.13" -content-hash = "d6be01698b1a28f1f259bf849d1dded95dfca23c6c86933b9becc5f4518a46f6" +content-hash = "ec642e35625eea4833635ed0d7083623ff04730f997b82cb212b2e8a23649265" diff --git a/pyproject.toml b/pyproject.toml index 9a6cecc..e0d8cf8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,7 @@ frozendict = "^2.3.9" html5lib = "^1.1" loguru = "^0.7.0" networkx = "^3.2.1" -pandas = "^2.1.4" +pandas = "2.1.4" pgeocode = "^0.4.1" psycopg2-binary = "^2.9.7" pymongo = "^4.6.0" @@ -101,6 +101,7 @@ seaborn = "^0.13.0" jupyter = "^1.0.0" myst-parser = "^1.0.0" nbsphinx = "^0.9.2" +pandoc = "^2.3" sphinx = "*" sphinx-copybutton = "^0.5.2" sphinx-git = "^11.0.0"