AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

Ein Thema von Benmik · begonnen am 25. Aug 2017 · letzter Beitrag vom 11. Sep 2017
Antwort Antwort
Seite 1 von 2  1 2   
Benmik

Registriert seit: 11. Apr 2009
441 Beiträge
 
Delphi 10.3 Rio
 
#1

Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 25. Aug 2017, 23:36
Ich habe eine Datenbank, aus der ich Häufigkeiten und Kreuztabellen (mit zwei, aber auch drei Variablen) mittels SQL ermittle.

Ich möchte jetzt das Ganze auf reines Delphi reduzieren, die Datenbank als zweidimensionales Array (ca. 250 Felder, ca. 3000 Datensätze) abbilden und die SQL-Befehle nachbauen.

Die Algorithmen für diese SQL-Befehle suche ich jetzt.
Bei einer einfachen Häufigkeit würde ich zum Beispiel die 3000 Werte des betreffenden Feldes in ein eindimensionales Array kopieren und das Array dann mittels Quicksort sortieren.
Aber vielleicht gibt es hierfür und vor allem für eine Kreuztabelle mit 2 und 3 Variablen schon fertige Lösungen?

Eigentlich müsste doch auch eine Sortierfunktion reichen, die ein zweidimensionales Array nach 3 Feldern sortieren kann?

Geändert von Benmik (25. Aug 2017 um 23:59 Uhr)
  Mit Zitat antworten Zitat
jobo

Registriert seit: 29. Nov 2010
2.963 Beiträge
 
Delphi 2010 Enterprise
 
#2

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 26. Aug 2017, 20:10
Vielleicht kannst Du etwas präziser beschreiben, welche Dimension Du als Ausgangssituation hast und was es werden soll.
Aus Deiner Beschreibung wird mir nicht so richtig klar, was IST ist und was SOLL soll.

Und auch wenn es nicht die Frage war:
Was ist der Anlass? Warum nicht SQL? Es gibt ein paar DB, die das ganz gut können, Statistik dann sowieso.

Der Ausgangspunkt einer Kreuztabelle wäre für mich bspw. eine Tabelle mit konkreten ID (Primärschlüssel), einer Kategorie/Referenz und einem Wert. Davon hätte ich vielleicht 3000 Datensätze, mit 250 Referenzen/Kategorien. Als Kreuztabelle ergäbe das 250 Spalten mit ein paar Zeilen.
Gruß, Jo
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
441 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 27. Aug 2017, 11:09
Hallo jobo, bin etwas erstaunt, dachte, die Fragestellung wäre recht einfach. Irrtum offenbar.

Es geht um ein Auswertprogramm für eine jährliche Datenerhebung, die seit über 10 Jahren läuft. Sie liegt im DBF-Format vor. Ich lese sie mit TDbf ein (dessen Aktualisierung schon nervig genug ist) und werte die Abfragen mit AbsoluteDatabase aus (da AbsDB In-Memory-Tables bietet). Das klappt alles einwandfrei.

Jetzt würde ich mich gern unabhängig von AbsDB machen, dessen umfangreiche DB-Funktionalität ich überhaupt nicht brauche. Die Daten sind statisch und werden ausschließlich gelesen (außer beim Einlesen der DB), und Mehrbenutzer ist auch nicht notwendig.

Hauptgrund ist aber die jährliche Aktualisierung. Die Erhebung wird jedes Jahr etwas verändert. Die Variablennamen werden nach Gruppen geordnet fortlaufend nummeriert. Fällt auch nur eine Variable weg oder wird hinzugefügt, ändert sich die Bezeichnung aller nachfolgenden. Dieses Jahr ist die 4. Variable weggefallen. Jetzt stehe ich vor nervtötenden Aufgabe, 100 Variablennamen, Bezeichnungen und Wertebezeichnungen neu anzupassen. (Auf die Struktur der DB habe ich keinerlei Einfluss).

Daher habe ich mich entschlossen, die lang gehegte Absicht anzugehen, das Programm generisch zu gestalten. Hierfür habe ich ein Konzept, das funktionierten müsste. Dazu brauche ich volle Gestaltung, was mit einem DB-Programm nicht möglich ist.

Ich habe keine Ahnung, nach welchem Algorithmus die SQL-Befehle von AbsDB arbeiten. Ich habe mich entschlossen, einfach die Kirche im Dorf zu lassen. Einfache Zähl- und Sortiervorgänge auch von einer Million Daten sind selbst bei älteren Prozessoren dermaßen schnell, dass auch deutlich suboptimale Algorithmen unter einer Sekunde brauchen. Das reicht völlig.

Ich kam dann relativ rasch darauf, dass bei diesem Ansatz das Problem darin besteht, ein zweidimensionales Array zu sortieren. In VB kein Problem, in Delphi augenscheinlich schon! Ich habe mich dann - wie so oft - nach diesem Beitrag von Altmeister David Heffernan gerichtet.

Mein Ansatz ist also bisher folgender:

1. Deklaration einer Klasse mit einem TStringDynArray als einzigem Inhalt (= Datensatz)
2. Deklaration einer Klasse TObjectList vom obigen Typ.
3. Einlesen der DBF-Daten über TDbf als string (ja, ja!)

Das Einlesen per TDbf, Überführen in die Liste inklusive Umwandeln zu string sowie testweise Sortieren nach einer Integervariable (mit 3.000 Mal Umwandeln von string zu integer im Comparer) dauert keine Sekunde auf einem Notebook mit einem älteren i3. Feierabend!

Mein weiteres Vorgehen wäre jetzt so, dass ich sortiere, zähle und das Ergebnis in die Form bringe, die mir zurzeit von SQL geliefert wird, damit ich den bisherigen Code nahtlos weiterverwenden kann. Bei Kreuztabellen mit 2 oder gar 3 Variablen würde ich dann immer die erforderlichen kleinen Abschnitte der Liste in eine temporäre Arbeitsliste kopieren, sortieren und zählen. Einfacher wäre es vermutlich, Quicksort den Bereich des zu Sortierenden zu übergeben, aber dann müsste ich direkt auf Quicksort gehen. Da nur die Referenzen kopiert werden und alles im Arbeitsspeicher abläuft, gehe ich davon aus, dass das so blitzschnell vor sich geht, dass auch diese Suboptimalität keine praktischen Konsequenzen hat.

Das ist jetzt mein Stand. Alles etwas vom Hobbyhandwerker, aber wenn's funktioniert?
Wenn natürlich jemand mit einer Profilösung um die Ecke kommt - herzlich willkommen!
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.325 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 28. Aug 2017, 13:32
Ich vermute so wie du den Begriff Variable benutzt, meinst du eigentlich Feldname.
Variablennamen sind für Anwender nicht sichtbar.

Warum sind andere Feldnamen für dich ein Problem?
Kannst du ein bischen Beispielcode zeigen, vor und nach deiner Umbenennung (Ist und Soll).

Mir erschließt sich nicht, wie eine Abkehr von SQL dein Problem lösen soll.
Insbesondere wenn du SQL-Befehle selbst implementieren willst.
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
441 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 29. Aug 2017, 20:35
Gut, dann beschreibe ich den typischen Fall:

Im ersten Jahr sieht der Fragebogen so aus:

1. Wie alt sind Sie (Jahre)?
2. Wie groß sind Sie (cm)
3. Welches Geschlecht haben Sie (m/w)?
4. Wie lautet Ihre PLZ?
5. Wieviele Personen leben in Ihrem Haushalt
a) Erwachsene?
b) Kinder?

Dies führt zu folgenden Feldnamen: V01,V02,V03,V04,V05a,V05b. Den vorhandenen Feldern wird von mir ein weiteres namens "Altersgruppe" hinzugefügt, dessen Werte aus der Variable (sic!) "V01" errechnet wird.

Im nächsten Jahr fällt das Feld "Alter" aus Diskriminierungsgründen weg. Das Feld "Geschlecht" hat nun die möglichen Werte "so genannt weiblich, so genannt männlich, Transgender, weiß nicht, sage ich nicht, Sonstiges", zudem heißt es nun "Sexuelle Orientierung". Außerdem rückt es an die erste Stelle und wird zu V01. Die Feldernamen heißen nun V01,V02,V03,V04a,V04b - mit nun zum Teil anderen Feldbezeichnungen, Wertbezeichnungen, Wertstrukturen.

Im Jahr darauf wird statt der PLZ das Bundesland abgefragt. Die Wertbezeichungen ändern sich von Bezeichnung gleich Wert zum Namen der 16 Bundesländer, der Typ von Integer zu string. Aus Layoutgründen rückt das Feld an die zweite Stelle. Das Alter wird nun wieder abgefragt, da herausgekommen ist, dass sich 18- und 80-Jährige trotz allem doch unterscheiden. Das Feld "Sexuelle Orientierung" heißt nun "Sexuelle Ichbestimmung" und erhält zusätzlich ein alphanumerisches Freifeld, das Feld wird daher in a) und b) erweitert. Die Körpergröße wird nun auf 0,5 cm genau abgefragt, der Typ ändert sich von Integer zu Float. Das Layout und damit die Reihenfolge der Felder wird komplett geändert, die Feldnamen damit auch. Die errechneten Felder - von denen es mehr gibt als in der DB sind - müssen aus immer wieder anders bezeichneten Feldern bestimmt werden.

Natürlich muss das Programm alle Datenbanken aller Jahre einlesen und richtig verarbeiten und alles richtig bezeichnen können. Tut es auch, weil ich einfach für jedes Jahr einen kompletten Satz von Bezeichnungen und Berechnungen erstellt habe. Ändert sich das drittletzte Feld, ist das Leben leicht. Fallen - wie in diesem Jahr - von den ersten 10 Feldern 5 weg, wird es bitter.

Ich habe mir daher ein System überlegt, wie ich gleichbleibende Felder (fast immer >95%) nur einmal beschreibe und der Position in der DB zuordne, egal wie sich der Feldname geändert hat. Ändert sich ein Feld, erstelle ich eine neue Beschreibung. In jedem Jahr muss ich nun nur die richtige Beschreibung der Position in der DB zuweisen, gleichbleibende Abschnitte (meist 90% ) kann ich einfach kopieren.

Ich frage mich nur, wo die tausend anderen Leute sind, die doch genau das gleiche Problem haben müssen.
  Mit Zitat antworten Zitat
mensch72

Registriert seit: 6. Feb 2008
828 Beiträge
 
#6

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 29. Aug 2017, 21:11
das letzt genannte riecht doch ganz stark nach dem Grundsatz-Workflow "1. Typisieren", "2. Klassifizieren", "3. Normalisieren", "4.Anylsieren", "5.Auswerten"

Erst DANN/SO kann man ja eh überhaupt absolute numerische oder binäre Regeln ala Normal-Values/Ranges anwenden...
So aufbereitet kümmern sich um die DetailAnalyse dann aber besser SVMs (SupportVectorMaschines) oder wenn man Zeit hat auch NNs (NeuronaleNetze möglichst mit endlicher aber dafür kontinuierlicher BackPropagation!).

Solche Sachen per letzendlicher Kreuztablellen rein zweidimensional angehen zu wollen nenne ich mal "sportlichen Ehrgeiz"... wenn es klappt HURRA, dann veröffentlichen und kassieren!

Geändert von mensch72 (29. Aug 2017 um 21:17 Uhr)
  Mit Zitat antworten Zitat
jobo

Registriert seit: 29. Nov 2010
2.963 Beiträge
 
Delphi 2010 Enterprise
 
#7

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 30. Aug 2017, 10:53
Offenbar gibt es sehr unterschiedliche Vorstellungen zum Begriff, Kreuztabellen, etc. Was mensch72 vorschlägt, habe ich entweder nicht verstanden oder geht über die Anforderung hinaus?

Vielleicht kann der TE nun anhand seiner Beschreibung (Jahr 1) mal darstellen, wie er die Kreuztabelle nun darstellt. Alle Spalten, ein paar Beispieldaten.
Außerdem: Gibt es irgendwelche Notwendigkeiten, verschiedene Jahrgangsdaten zu verknüpfen?
Welche Rolle spielt die Reihenfolge v01-v05? Ist das nicht beliebig, also am Ende eine reine Darstellungs- oder Labelfrage?
Gruß, Jo
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.325 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 30. Aug 2017, 13:17
Die Ausgangsdaten sind also in einer Tabelle enthalten, deren Feldnamen und Feldreihenfolge sich von Jahr zu Jahr ändern.
Dabei können Felder entfallen oder neue hinzukommen.

Eine Software soll natürlich im Kern nicht verändert werden.
Aber was ist bei dir der Kern? Dazu ein Beispiel.

Es soll eine Ergebnismenge aus einer Menge von Feldern berechnet werden, deren Inhalt für den Anwendungsfall fest definiert ist.
Diese Vorschrift soll sich nicht ändern. Es muss dafür gesorgt werden, das diese Felder immer verfügbar sind.
Eine Möglichkeit wäre die Tabelle durch eine View zu kapseln, die du Jahr für Jahr anpasst.
Innerhalb der View können Hilfstabellen oder Datenbankprozeduren benutzt werden, um die Daten aufzubereiten.
Code:
CREATE VIEW V_EINGANGSDATEN(
    SPALTE1,
    SPALTE2,
    SPALTE3)
AS
select v01 spalte1, v03 spalte2, v05b + v05a spalte3
from  t_eingangsdaten
where (v02 = 0)
;

select spalte1, spalte2, spalte3 from v_eingangsdaten;
Alle Abfragen richten sich nur an die View, Änderungen sind dann nur an einer Stelle notwendig.
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
441 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 30. Aug 2017, 15:48
Ich finde es jetzt auch schwer, einen Weg von mensch72s Vorschlägen zu einer praktischen Implementierung zu finden.
Einen VIEW kannte ich noch nicht. Er würde aber nicht das Problem der wechselnden Feld- und Wertbezeichnungen lösen, die dem Anwender angezeigt werden müssen.

Nochmal: Auf die Struktur der DB habe ich keinen Einfluss. Wenn V01 im ersten Jahr das Alter ist, im zweiten die Größe und im dritten die PLZ, dann ist das so. Der Anwender hat 1 - 3 Klapplisten, in die in der Reihenfolge des Auftritts in der DB alle Felder (mit ihren Feldbezeichnungen) eingetragen sind. Aus diesen Listen wählt er dann die Felder für die einfache Häufigkeit oder eine Kreuztabelle mit 2 oder 3 Feldern aus. Das Programm muss dann immer wissen, ob V01 im gegebenen Jahr als "Alter", "Größe" oder "PLZ" als erster Eintrag in der Klappliste erscheinen muss.

Die von mir im stillen Hirnkästlein ersonnene Lösung, die noch der Bestätigung durch eine praktische Implementierung harrt, sieht so aus:

1. Für das erste Jahr erstelle ich eine Enumeration, also ungefähr so: type TFeldpos = (fAlter01,fGröße01,fGeschlecht01,fPLZ01,fPersImHHE01,fPersImHHK01) .

2. Ich definiere eine Klasse TFeld mit allen Informationen, die ich über ein Feld brauche; also z.B. die laufende Nummer (die Enumeration), Typ, Bezeichnung, mögliche Werte, Wertbezeichungen und Weiteres.

3. Ich definiere eine hardkodierte Liste type TFeldListe = class(TObjectList<TFeld>) , in die die bisher vorhandenen 6 Felder aufnommen werden. Dabei erstelle ich die 6 bisher vorhandenen TFeld .

4. Zur Laufzeit erstelle ich eine weitere Liste type TDBListe = class(TObjectList<TFeld>) und füge per Add die Objekte der FeldListe hinzu. Im ersten Jahr ist das natürlich einfach.

5. Im Betrieb gilt: Listindex Klappliste = Pos Feld in DB = Pos Feldobjekt in der DBListe. Damit sollte die Handhabung leicht funktionieren. An die Eigenschaften des Feldes in der DBListe komme ich über FeldListe[DBListe[xx].LfdNr] (= TFeldPos ) heran.

6. Die Berechnung der Altersgruppen läuft über den Eintrag in der DBListe, der FeldListe[fAlter01] entspricht.

Jetzt kommt das zweite Jahr und es wird spannend.

Das Feld "Geschlecht" hat sich geändert. An die 7. Stelle der Enumeration kommt jetzt fGeschlecht02 , der FeldListe wird ein 7. Objekt hinzugefügt. Die Erstellung der DBListe beginnt mit DBListe.Add(FeldListe[fGeschlecht02]); .

In allen folgenden Jahren geht es analog. Für jede neue oder geänderte Variable wird ein neues TFeld erstellt und an FeldListe angehängt. Die jährliche Arbeit besteht dann darin, eine neue, jahresspezifische DBListe zu erstellen. Wenn sich jetzt aber zwischen V04 und V82 nichts ändert, dann kann ich die Add von V05 - V81 einfach kopieren. Wird ein geändertes Feld für eine Berechnung verwendet, dann kommt eben eine If..Then - Konstruktion zum Einsatz.

In Betrachtung dessen, was sich in den letzten über 10 Jahren wie oft und in welcher Form geändert hat, sagt mein Hirnkästlein, das müsste funktionieren. Was Delphi dazu sagt, das könnte leider was ganz anderes sein...

Geändert von Benmik (30. Aug 2017 um 16:09 Uhr)
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.325 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Häufigkeiten und Kreuztabellen aus zweidimensionalem Array errechnen

  Alt 31. Aug 2017, 10:11
Alles was sich ändert würde ich aus einer Konfigurationsdatei oder einer Datenbank lesen.
Auch mögliche Werte, Wertbezeichungen, usw.
Selbst welche Ergebnisfelder es gibt und die zugehörige Berechnungsvorschrift kann man dort ablegen.

Vieleicht ist die Beschreibung der IDEA-Schnittstelle in dem Zusammenhang interessant:
https://audicon.net/downloads/330
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +2. Es ist jetzt 01:13 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf