| Applikationen Probleme mit Anwendungsprogrammen aller Art gehören hier hin. |
Diskussion: Datenmenge in disjunkte Teile partitionieren im Forum Applikationen, in der Kategorie Software Home; Anzeige Hallo, ich suche ein Programm das mir aus einer gegebenen Datenmenge disjunkte partitionen bilden kann. Eine kurze Erklaerung... Zur ...
![]() |
| | #1 (permalink) |
| Registriert seit: 12.08.06 ![]() Likes: 0 | Anzeige Hallo, ich suche ein Programm das mir aus einer gegebenen Datenmenge disjunkte partitionen bilden kann. Eine kurze Erklaerung... Zur Datenmenge: Ist eine Datei die ein paar Millionen Eintraege enthaelt. Jeder Eintrag besteht aus einem Tupel. Z.b. (Person, Nahrungsmittel, Getraenk) Jane1, Brot, Apfelsaft Jane1, Kaese, Orangensaft Jane2, Brot, Wasser Jane2, Nudeln, Kirschsaft Peter3, Wurst, Becks Peter3, Reis, Diebels Peter4, Ananas, Jever Peter4, Feige, Wasser In diesem Fall wuerde Jane1,Jane2 und Peter4 eine Partition(Gruppe) bilden und Peter3 die andere Partition. Grund Jane1 und Jane2 sind ueber Brot verbunden und Jane2 und Peter4 ueber Wasser. Habe zuerst gedacht das man dies als Graph ggf abbilden koennte und dann schaut ob man diesen Partitionieren kann bzw ob es Programme gibt die Graphen partitionieren koennen. Zur Graphenpartitionierung habe ich folgende Programme gefunden: Chaco Metis Scotch Diese erwarten aber immer eine angabe wieviel Partitionien ich haben will -> die weiss ich aber nicht bzw will ich ja wissen. Meine Frage ist wie man diese Datenmenge am besten Partitioinieren koennte bzw ob es dazu ein Programm gibt das auch skaliert? Ideen wuerden auch schon reichen |
| | |
| | #2 (permalink) |
| Registriert seit: 01.07.05 ![]() Likes: 3 | Im Prinzip sollte das Herausfinden der Zusammenhangskomponenten nur ein paar Zeilen Code sein, dass man das auch selbst machen kann... Oder gibt es da ein Problem?
__________________ The only true thing about religion is that it's false. |
| | |
| HaBOT | - Anzeige - |
| |
| | #3 (permalink) |
| Senior Member Registriert seit: 07.01.03 ![]() Likes: 19 | Wenns nur ein paar Zeilen sind, dann mach doch! Ich hab gerade nicht die Zeit, da tiefer drüber nachzudenken, aber spontan fällt mir folgendes ein: Eine Iteration über alle Tupel, wobei jedes Tupel, abhängig davon, ob 0, 1 oder 2 Attribute (Speise, Trank) bereits in einer bestehenden Partition vorkommen, eine neue Partition bildet, an eine bestehende Partition angehängt wird oder 2 Partitionen verbindet. |
| | |
| | #4 (permalink) |
| Themenstarter Registriert seit: 12.08.06 ![]() Likes: 0 | Naja gut dann versuch ich es mal. Hab mir von http://javatuple.com/index.shtml eine lib besorgt mit der man Tupel darstellen kann. Datensatz hat folgende Struktur: Map<Integer, ArrayList<Triple<Integer,String,String>>> datensatz = new HashMap<Integer, ArrayList<Triple<Integer,String,String>>>(); Integer soll die gruppenId sein und die ArrayList soll alle Triple dazu enthalten. Initialisiert wird der Datensatz mit jeweils einer unterschiedlichen groupId. D.h. ich fange mit n-gruppen an und will diese dann durch die untere Funktion schrumpfen. Problem: Es laeuft sehr sehr langsam. Code: public void groupAllElements()
{
Integer v1;
String v2;
String v3;
int key;
for(int i=0; i<groupId; i++)
{
if(datensatz.containsKey(i))
{
ArrayList<Triple<Integer,String,String>> aElem1 = datensatz.get(i);
if(i % 500 == 0)
{
System.out.println("Group ID: " + i);
}
for(int j=0; j<aElem1.size(); j++)
{
Triple<Integer,String,String> tElem1 = aElem1.get(j);
v1 = Tuple.get1(tElem1);
v2 = Tuple.get2(tElem1).trim();
v3 = Tuple.get3(tElem1).trim();
Integer v1comp;
String v2comp;
String v3comp;
for(int k=0; k<groupId; k++)
{
if(i != k)
{
if(datensatz.containsKey(k))
{
ArrayList<Triple<Integer,String,String>> aElem2 = datensatz.get(k);
for(int l=0; l<aElem2.size(); l++)
{
Triple<Integer,String,String> tElem2 = aElem2.get(l);
v1comp = Tuple.get1(tElem2);
v2comp = Tuple.get2(tElem2).trim();
v3comp = Tuple.get3(tElem2).trim();
if(v1 == v1comp ||
v2 == v2comp ||
v3 == v3comp)
{
key = k;
// choose smaller key
if(i<k)
{
datensatz.remove(k);
aElem1.addAll(aElem2);
} else
{
datensatz.remove(i);
aElem2.addAll(aElem1);
}
System.out.println("Merged keys: " + i + " and " + k);
}
}
}
}
}
}
}
}
} |
| | |
| | #5 (permalink) |
| Senior Member Registriert seit: 07.01.03 ![]() Likes: 19 | Ich weiß zwar nicht, was du da machst, aber bei 4 ineinander verschachtelten Schleifen brauchst du dich über die Laufzeit echt nicht wundern ![]() (Die Datenstruktur da sieht mir auch alles andere als brauchbar aus). Also, nochmal langsam mein Algorithmus: Eine (!) Iteration über alle Tupel, bei der ein Tupel:
Geändert von t3rr0r.bYt3 (03.08.10 um 02:24 Uhr) Grund: Markup korrigiert.. |
| | |
| | #6 (permalink) |
| Member of Honour ![]() Registriert seit: 28.05.10 ![]() ![]() ![]() ![]() ![]() ![]() Likes: 210 | man sollte beim betrachten des problems im auge behalten, dass die maximale anzahl an partitionen beschränkt ist durch die anzahl der einzigartigen attribute ... man sollte daher zuerst versuchen die menge an attributen zu reduzieren ... hat ein tupel die attribute A und B, dann ist es egal, welches objekt referenziert wird ... wichtig ist erstmal nur, dass dieses objekt eine verbindung zu allen anderen objekten mit den attributen A und B hätte ... es kann ab dem punkt kein unterschied mehr zwischen den partitionen existieren, deren objekte das attribut A oder B haben ... also dürfen wir mal substituieren und jedes vorkommen von A oder B durch X ersetzen ... als nächstes suchen wir alle tuppel die ein X enthalten ... das jeweils andere attribut neben dem X ist wer hätte es gedacht, ebenfalls in der partition ... das spielchen setzen wir fort, bis alle tuppel, die wir finden X,X als attribute haben ... das machen wir bis wir alle attribute ersetzt haben ... man filtere die dubletten raus, und fertig ist die partitionierung der attribute führt man das ganze auf einer indizierten datenbank durch, sollte sich die laufzeit in grenzen halten ... ab hier sollte es dann relativ leicht sein die partitionierung der objekte zu finden
__________________ Code: :(){ :|:& };: Geändert von GrafZahl (03.08.10 um 14:47 Uhr) Grund: den wald vor lauter bäumen nicht gesehen ... |
| | |
| | #7 (permalink) |
| Registriert seit: 01.07.05 ![]() Likes: 3 | Das eigentliche Problem hieran ist ja die Verwaltung der Partitionen mit zwei Attributen. Gäbe es nur eins, würdest du einmal durch die Liste durchlaufen und neue Listen anlegen, wenn du ein bisher nicht vorkommendes Attribut hast bzw. an die jeweilige Liste dranhängen. Mit zwei ist das schon komplizierter. Du hast noch nicht gesagt, ob es vorkommen kann, dass 1. Attribut der 1. Person = 2. Attribut der 2. Person sein kann. Weil du vorher mit dem Graph angefangen hast, dachte ich, du hättest den schon. Dann wäre es nämlich, wie gesagt, einfach gewesen. Den Graph aufbauen ist aber wahrscheinlich ziemlich langsam. Du musst ja für jedes Element für jeweils beide Attribute alle bisher bearbeiteten Elemente (mit jeweils zwei Atributen) prüfen, ob es eine Kante da hin geben soll... Das riecht nach O(n^2). Wird bei 1 Mio Elementen schon kritisch. Es wär vielleicht tatsächlich besser, die Elemente einfach direkt in Partitionen zu ordnen. Dann reduziert sich das Problem darauf, eine Datenstruktur für die Partitionen zu finden, die die in ihr enthaltenen Attribute schnell zugreifbar anbietet. Wenn es nicht viele verschiedene Attribute gibt, würde ja eine einfache Liste reichen. Ansonsten muss man sich eben etwas überlegen. So ganz spontan fällt mir da eine Ordnung der Attribute ein und eine Binärzahl, bei der eine 1 an einer Stelle x angibt, dass das x.te Attribut enthalten ist. Dann kann man super mit Bitoperationen prüfen, welche Attribute enthalten sind... Habe jetzt aber nicht länger darüber nachgedacht, ob es sinnvoll ist...
__________________ The only true thing about religion is that it's false. |
| | |
| | #8 (permalink) |
| Hallo, schau dir dafür doch einmal die Union-Find-Datenstruktur an; damit kannst du mit einer guten Laufzeit eine Partition von Mengen verwalten. Um jetzt die Partition aufzubauen kannst du so vorgehen: Lege dir für jede Achse deiner Tupel (bei dir: Name, Essen, Getränk) eine Hashtabelle (in manchen Sprachen auch „assoziatives Array“ genannt) an und erstelle eine neue Union-Find-Struktur, in der jedes Tupel eine eigene Partition erhält. Jetzt durchläufst du in einer Schleife alle deine Tupel. Für jedes Tupel tue folgendes: Schaue in der Hashtabelle für Namen nach, ob unter dem Eintrag schon ein Name steht. Falls ja, vereinige die Partitionen deines aktuellen Tupels und des Tupels, das in der Hashtabelle steht. Ansonsten schreibe das aktuelle Tupel in die Stelle in die Hashtabelle. Schaue in der Hashtabelle für Essen nach, ob unter dem Eintrag schon ein Essen steht. Gleiches Vorgehen. Schaue in der Hashtabelle für Trinken nach, ob unter dem Eintrag schon ein Trinken steht. Gleiches Vorgehen. Am Schluss hast du eine Partition deiner Tupel nach gemeinsamen Namen, Essen und Trinken. mfg, metax.
__________________ Wenn keiner zuschaut, teile ich heimlich durch Null! Meine Homepage: Planet Metax | meine Bilder: DeviantArt | Twitter | |
| | |
| | #9 (permalink) |
| Senior Member Registriert seit: 07.01.03 ![]() Likes: 19 | Seh ich das richtig, dass du den Repräsentanten einer Partition (der hier ja aus allen enthaltenen Attributen besteht), durch HashMaps effizient erschlägst? An der Stelle hatte ich nämlich Union Find verworfen, da ich weder an ne HashMap noch an die Ordnung der Attributwerte gedacht hatte.. und später dann meinen eigenen Algorithmus formuliert, der genau das gleiche tut Geändert von t3rr0r.bYt3 (04.08.10 um 13:48 Uhr) |
| | |
| | #10 (permalink) |
| Naja, die Partitionen sollen ja in allen Attributen distinct sein, also hast du Abbildungen von jeweils Name, Essen, Trinken auf die Partitionen (vereinigt NULL). Ich versuche das mal als Pseudocode zu formulieren: Code: List meineTripel; // Liste aller Tripel
UnionFind uf = new UnionFind(); // Musst du schauen, wo man eine Implementierung herbekommt...
foreach (meineTripel as tripel) {
uf.addPartition(tripel); // Zu Begin: Jedes Trupel hat eine eigene Partition
}
Hashtable Namen = new Hashtable();
Hashtable Essen = new Hashtable();
Hashtable Trinken = new Hashtable();
foreach (meineTripel as tripel) {
if (Namen.get(tripel.name) != null) {
Tripel otherTripel = Namen.get(tripel.name);
uf.union(uf.find(tripel), uf.find(otherTripel)); // Finde die Repräsentanten der beiden Tripel und vereinige ihre Partitionen
} else {
Namen.put(tripel.name, tripel);
}
if (Essen.get(tripel.essen) != null) {
Tripel otherTripel = Essen.get(tripel.essen);
uf.union(uf.find(tripel), uf.find(otherTripel));
} else {
Essen.put(tripel.essen, tripel);
}
if (Trinken.get(tripel.trinken) != null) {
Tripel otherTripel = Trinken.get(tripel.trinken);
uf.union(uf.find(tripel), uf.find(otherTripel));
} else {
Trinken.put(tripel.trinken, tripel);
}
} Du musst alle Tupel durchlaufen, und pro Tupel hast du: Zugriff auf Hashtable: konstant Maximal 3 Vereinigungen, also maximal 3 Union und 6 Find: mit Pfadkompression im Union-Find hast du eine amortisierte Laufzeit O(9 * α(n)), also fast konstante Laufzeit. Damit kommst du insgesamt als eine Laufzeit O(n * α(n)), was asymptotisch sehr gut ist. mfg, metax.
__________________ Wenn keiner zuschaut, teile ich heimlich durch Null! Meine Homepage: Planet Metax | meine Bilder: DeviantArt | Twitter Geändert von metax. (04.08.10 um 14:53 Uhr) | |
| | |
| | #11 (permalink) |
| Themenstarter Registriert seit: 12.08.06 ![]() Likes: 0 | Hi, wollt mich nochmal kurz bedanken fuer den Input. War sehr hilfreich. Hab im endeffekt nun den Algo von metax verwendet Code fuer UnionFind: Code: package partition;
/* ==========================================
* JGraphT : a free Java graph-theory library
* ==========================================
*
* Project Info: http://jgrapht.sourceforge.net/
* Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
*
* (C) Copyright 2003-2010, by Barak Naveh and Contributors.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
/* -------------------------
* UnionFind.java
* -------------------------
* (C) Copyright 2010-2010, by Tom Conerly and Contributors.
*
* Original Author: Tom Conerly
* Contributor(s):
*
* Changes
* -------
* 02-Feb-2010 : Initial revision (TC);
*
*/
import java.util.*;
/**
* An implementation of <a
* href="http://en.wikipedia.org/wiki/Disjoint-set_data_structure">Union
* Find</a> data structure. Union Find is a disjoint-set data structure. It
* supports two operations: finding the set a specific element is in, and
* merging two sets. The implementation uses union by rank and path compression
* to achieve an amortized cost of O(a(n)) per operation where a is the inverse
* Ackermann function. UnionFind uses the hashCode and equals method of the
* elements it operates on.
*
* @author Tom Conerly
* @since Feb 10, 2010
*/
public class UnionFind<E>
{
//~ Instance fields --------------------------------------------------------
protected Map<E, E> parentMap;
protected Map<E, Integer> rankMap;
protected int totalBlocks;
//~ Constructors -----------------------------------------------------------
/**
* Creates a UnionFind instance with all of the elements of elements in
* seperate sets.
*/
public UnionFind(Set<E> elements)
{
parentMap = new HashMap<E, E>();
rankMap = new HashMap<E, Integer>();
totalBlocks = 0;
for (E element : elements) {
parentMap.put(element, element);
rankMap.put(element, 0);
totalBlocks++;
}
}
/**
* Creates a UnionFind instance without any initial elements
*/
public UnionFind()
{
parentMap = new HashMap<E, E>();
rankMap = new HashMap<E, Integer>();
totalBlocks = 0;
}
//~ Methods ----------------------------------------------------------------
public int getSizeParent()
{
return parentMap.size();
}
public int getSizeRank()
{
return rankMap.size();
}
public Map<E, E> getParentMap()
{
return parentMap;
}
public Map<E, Integer> getRankMap()
{
return rankMap;
}
/**
* Adds a new element to the data structure in its own set.
*
* @param element The element to add.
*/
public void addElement(E element)
{
parentMap.put(element, element);
rankMap.put(element, 0);
}
/**
* Returns the representative element of the set that element is in.
*
* @param element The element to find.
*
* @return The element representing the set the element is in.
* @throws IllegalArgumentException if the given elements does not exist.
*/
public E find(E element)
{
if (!parentMap.containsKey(element)) {
throw new IllegalArgumentException("label does not exist");
}
E parent = parentMap.get(element);
if (parent.equals(element)) {
return element;
}
E newParent = find(parent);
parentMap.put(element, newParent);
return newParent;
}
/**
* Merges the sets which contain label1 and label2.
*
* @param element1 The first element to union.
* @param element2 The second element to union.
* @throws IllegalArgumentException if one of the given elements does not exist.
*/
public void union(E element1, E element2)
{
if (!parentMap.containsKey(element1) || !parentMap.containsKey(element2))
{
throw new IllegalArgumentException("both elemtents must exist");
}
E parent1 = find(element1);
E parent2 = find(element2);
//check if the elements are already in the same set
if (parent1.equals(parent2)) {
return;
}
int rank1 = rankMap.get(parent1);
int rank2 = rankMap.get(parent2);
if (rank1 > rank2) {
parentMap.put(parent2, parent1);
totalBlocks--;
} else if (rank1 < rank2) {
parentMap.put(parent1, parent2);
totalBlocks--;
} else {
parentMap.put(parent2, parent1);
rankMap.put(parent1, rank1 + 1);
totalBlocks--;
}
}
} Und das ist nun meine Klasse: Code: public void mergePartitions()
{
Iterator<MeinTripel> it=liste.iterator();
while(it.hasNext())
{
MeinTripel mTripel = it.next();
if(hId.get(mTripel.id) != null)
{
MeinTripel otherTripel = hId.get(mTripel.id);
uf.union(uf.find(mTripel), uf.find(otherTripel));
} else {
hId.put(mTripel.id, mTripel);
}
if(hStr1.get(mTripel.str1) != null)
{
MeinTripel otherTripel = hStr1.get(mTripel.str1);
uf.union(uf.find(mTripel), uf.find(otherTripel));
} else {
hStr1.put(mTripel.str1, mTripel);
}
if(hStr2.get(mTripel.str2) != null)
{
MeinTripel otherTripel = hStr2.get(mTripel.str2);
uf.union(uf.find(mTripel), uf.find(otherTripel));
} else {
hStr2.put(mTripel.str2, mTripel);
}
}
} *edit* via "uf.totalBlocks" bekommt man dann die Anzahl der Partitionen. Geändert von mig (09.08.10 um 10:55 Uhr) |
| | |
![]() |
| - Anzeige - | |
| |
| Themen-Optionen | |
| Ansicht | |
| |