def timed(*args, **kw): ts = time.time() result = method(*args, **kw) te = time.time() logger.debug('%r (%r, %r) %.3f sec' % (method.__name__, args, kw, te-ts)) return result
def MCLAlgorithm(self, inflation=3.3): """ Metoda wykonuje grupowanie za pomocą algorytmu MCL @param inflation: wartość współczynnika inflacji algorytmu MCL @requires: program MCL w ścieżce wykonywalnej @rtype: list @return: lista list z członkami grup """ try: nx.write_weighted_edgelist(self.graph, "/tmp/mcl-input", delimiter="\t") except: nx.write_edgelist(self.graph, "/tmp/mcl-input", delimiter="\t") import os logger.debug("Invoking mcl command ...") os.system("mcl /tmp/mcl-input --abc -te 2 -I %f -o /tmp/mcl-output" % inflation) logger.debug("MCL clustering done") out_file = open("/tmp/mcl-output", 'r') lines = out_file.readlines() partition = list() import string for line in lines: partition.append(map(int, string.split(line))) return partition
def rateQuality(self, hardGroupsNo = 0): ''' Wyznacza wskaźniki jakości działania metody autorskiej @type hardGroupsNo: number @param hardGroupsNo: liczba kolejnych (od najmniej licznej) grup, których członkowie będą uznani za podjerzanych @rtype: tuple @return: Krotka matchRate i popRate ''' if hardGroupsNo: self.selectGroups = [hardGroupsNo] for i in self.selectGroups: # pobierz pierwszych i grup matchCount = 0 # suspects = self.cq.smartGetFristNGroups(self.result, i) suspects = self.cq.getSuspectedGroups(self.result, i) logger.debug("# Podejrzani: ") logger.debug("# " + str(suspects)) for v in self.rings: if int(v) in suspects: matchCount += 1 matchRate = matchCount/len(self.rings) * 100.0 popRate = len(suspects)/self.vertexNo * 100.0 suspectsRate = matchCount/len(suspects) * 100.0 logger.info("%d ; %f ; %f" % (i, matchRate, popRate)) # liczba grup, procent wykrytych, procent podejrzewanje populacji return (matchRate, popRate, suspectsRate)
def calculateMinMax(self): """ Metoda pomocnicza. Zapisuje do pliku dziennika informacje o największej i najmniejszej wadze krawędzi w sieci. """ minEdge = min(self.graph.edges(data=True), key=lambda node: node[2]['weight']) self.minWeight = self.graph.get_edge_data(*minEdge[:2])['weight'] maxEdge = max(self.graph.edges(data=True), key=lambda node: node[2]['weight']) self.maxWeight = self.graph.get_edge_data(*maxEdge[:2])['weight'] logger.debug("Waga: max " + repr(self.maxWeight) + " and min " + repr(self.minWeight))
def newmanAlgorithm(self): """ Metoda wykonuje grupowanie za pomocą algorytmu Girvana-Newaman. @rtype: list @return: lista list z członkami grup """ from lib import newman (Q, partition) = newman.detect_communities(self.graph) # returns list o lists (each list for community) as a second tuple member logger.debug("Newman zrobiony") return partition
def causetNewmanAlgorithm(self, verbose=False): """ Metoda wykonuje grupowanie za pomocą algorytmu Caluseta-Newmana @rtype: list @return: lista list z członkami grup """ from lib import causet_newman (maxQ, partition, tree, treeRoot) = causet_newman.communityStructureNewman(self.graph) # returns list o lists (each list for community) as a second tuple member logger.debug("Causet-Newman zrobiony") return partition
def loadGraph(self, filename = 'fb.gpickle'): """ Ładuje sieć do pamięci z pliku typu python pickle. @param filename: nazwa pliku """ self.graph = nx.read_gpickle(filename) # anonimizacja grafu, każdemu węzłowi przypisywany jest numer i = 1 for node in self.graph: self.labels[node] = i i += 1 logger.info("########################## FACEBOOK EXPERIMENT ########################") logger.debug("Sieć załadowana, krawędzi: %d, węzłów: %d" % (self.graph.number_of_edges(), self.graph.number_of_nodes()))
def sliceGraph(self, threshold): """ Metoda służy do odfiltrowania z sieci połączeń o zbyt dużej wadze (świadczących o luźnych związkach pomiędzy węzłami). Jeżeli dawaj użytkownicy brali udział wspólnie w mniejszej ilości głosowań, niż określa parametr threshold, to krawędź pomiędzy węzłami reprezentującymi tych użytkowników jest usuwana. Następnie usuwane są wszystkie węzły, których stopień jest równy 0 (nie są połączone z żadnymi innymi węzłami) @type threshold: number @param threshold: Wartość progu. Minimalna liczba głosowań, w których użytkownicy musieli brać wspólnie udział, aby w sieci istniała krawędź ich łącząca. """ def filter(edge): if edge[2]['weight'] < threshold: self.graph.remove_edge(*edge[:2]) map(filter, self.graph.edges(data=True)) # usuń odłączone węzły def filterNodes(node): if self.graph.degree(node) == 0: self.graph.remove_node(node) map(filterNodes, self.graph.nodes()) # następuje przeliczenie wartości wag krawędzi. Wagi otrzymują docelową wartość, czyli taką, gdzie bardziej związane węzły są połączone # krawędzią o mniejszej wadze. W tym celu wagom zostaje przypisana wartość waga = 1/liczba_wspolnych_glosowan def invertWeight(edge): try: edge[2]['weight'] = int(100/edge[2]['weight']) except: edge[2]['weight'] = float('Inf') logger.error("Błąd przy wyliczaniu wagi krawędzi, ustawiono nieskończoność!!") # def nullifyWeight(edge): # edge[2]['weight'] = 1 map(invertWeight, self.graph.edges(data=True)) # map(nullifyWeight, self.graph.edges(data=True)) logger.debug("Wykonano filtrowanie z poziomem odcięcia: " + repr(threshold) + ", krawędzi " + repr(self.graph.number_of_edges()) + ", węzłów " + repr(self.graph.number_of_nodes()))
def blondelAlgorithm(self): """ Metoda wykonuje grupowanie za pomocą algorytmu Blodela et al. @rtype: list @return: lista list z członkami grup """ from lib import blondel d = blondel.best_partition(self.graph) # zwraca słownik węzłów z numerem grupy jako wartość logger.debug("Algorytm Blondela wykonany") # zamieniamy na listę list clusters = max(d.values()) nodeList = [None]*(clusters+1) for k in d.keys(): if not nx.utils.is_list_of_ints(nodeList[d[k]]): nodeList[d[k]] = [] nodeList[d[k]].append(k) return nodeList
def fetchGraph(self): """ Metoda pobiera informacje o znajomych i połączeniach pomiędzy nimi korzystając z Facebook Graph API. Sieć jest zapisywana w systemie plików jako serializowany obiekt python pickle. """ from simplejson import loads from urllib2 import urlopen from xml.dom import minidom logger.debug("Fetching facebook graph") friends = loads(urlopen('https://graph.facebook.com/me/friends?access_token='+TOKEN).read()) for friend in friends['data']: self.graph.add_node(int(friend['id']), name=friend['name']) self.graph.add_edge(self.myId, int(friend['id'])) foaf = minidom.parse(urlopen('https://api.facebook.com/method/friends.getMutualFriends?target_uid='+friend['id']+'&source_uid=1244349170&access_token='+TOKEN)) for f in foaf.getElementsByTagName("uid"): self.graph.add_edge(int(f.firstChild.nodeValue), int(friend['id'])) self.saveGraph()
def generate(self, number = 1, size = 5, target_size = 5, legal_target_size = 10,VOTERS=1000, OBJECTS=200, bad_hideout=False, slice_level = 0): """ Metoda generuje dane głosowania (listę obiektów wraz z indetyfikatorami głosujących, którzy oddali głos na dany obiekt) i zapisuje je do pliku określonego w self.path. @param number: liczba klik @param size: rozmiar kliki @param target_size: liczba obiektów, na które głosują członkowie kliki @param legal_target_size: średnie liczba obiektów, na które głosują uczciwi głosujący @param VOTERS: liczba głosujących @param OBJECTS: liczba obiektów @type bad_hideout: boolean @param bad_hideout: parametr mówu o tym, czy członkowie kliki nie głosują na obiekty nie będące ich zadanym celem. """ additional_votes = legal_target_size - target_size if additional_votes < 0: additional_votes = 0 objects = [[] for i in xrange(OBJECTS)] # każdy obiekt ma listę swoich głosujących import random self.voting_rings = [[] for i in xrange(number)] for i in xrange(number): for j in xrange(size): voter = str(random.randint(0, VOTERS)) while voter in self.voting_rings[i]: voter = str(random.randint(0, VOTERS)) self.voting_rings[i].append(voter) # członkowie kliki głosują na swoje cele for i in xrange(number): for j in xrange(target_size): target = random.randint(0, OBJECTS-1) objects[target].extend(self.voting_rings[i]) nonVotingCntr = 0 for voter in xrange(VOTERS): done_voting = False for ring in self.voting_rings: if str(voter) in ring: done_voting = True break if done_voting: if bad_hideout: nonVotingCntr += 1 continue else: votes = int(random.gauss(additional_votes, additional_votes/4.0)) else: votes = int(random.gauss(legal_target_size, legal_target_size/4.0)) for i in xrange(votes): target = random.randint(0, OBJECTS-1) if not str(voter) in objects[target]: objects[target].append(str(voter)) # logger.debug("Non voting cntr is %d" % nonVotingCntr) logger.debug("Kliki to:") logger.debug(self.voting_rings) file = open(self.path, 'w') o_number = 1 for o in objects: file.write(str(o_number) + "\n") file.write(" ".join(o)) file.write("\n") o_number += 1 file.close()
def compute(self, hardGroupsNo = 0, runsNo = 1): ''' Metoda wykonuje określoną w L{runsNo} liczbę uruchomień algorytmu, zwaraca średnią arytmetyczną wskaźników jakości. @type hardGroupsNo: number @param hardGroupsNo: liczba grup (począwszy od najmniej licznej), których członkowie są uważania za podjerzanych @rtype: tuple @return: Zwraca krotkę (matchRate, popRate, suspectsRate, near100rate), która zwiera średnią arytmetyczną z wartości wyznaczonych przez metodę L{rateQuality}. ''' logger.info("# Parametry generatora") logger.info("# " + str(self.paramsDict)) logger.info("# Liczba prób: %d" % runsNo ) logger.info("# Poziom odcięcia: %d" % self.paramsDict['slice_level']) matchRate = 0.0 matchRateList = [] popRate = 0.0 suspectsRate = 0.0 near100Rate = 0.0 for run in xrange(runsNo): self.dm.generate(**self.paramsDict) self.graph = self.gm.makeGraph() self.rings = sum(self.dm.voting_rings, []) # H-H-HHACKISH spłaszczenie listy list self.vertexNo = len(self.graph) self.cq = sna.Cliquer(self.graph) self.cq.sliceGraph(self.paramsDict['slice_level']) self.result = self.cq.blondelAlgorithm() tuple = self.rateQuality(hardGroupsNo) matchRate += tuple[0] matchRateList.append(tuple[0]) popRate += tuple[1] suspectsRate += tuple[2] # czwarty wskaźnik jakości if tuple[0] > 90: near100Rate += 1 logger.debug(near100Rate) matchRateAvg = float(matchRate/float(runsNo)) # obliczenie wariancji matchRate matchRateList = map(lambda rate: (rate - matchRateAvg)**2, matchRateList) matchRateVariance = 1.0/runsNo * sum(matchRateList) # wyznaczanie średnich arytmetycznych tuple = (float(matchRate/float(runsNo)), float(popRate / float(runsNo)), float(suspectsRate / float(runsNo)), float(near100Rate / float(runsNo))*100.0) logger.info("# Po %d uruchomieniach (procent wykrytych; procent populacji podjerzewany; procent faktycznych wśród podejrzewanych; procent podejść, gdzie wykryto powyżej 90 procent" % runsNo) logger.info(tuple) logger.info("# Dla parametrów generatora: ") logger.info(self.paramsDict) logger.info("# Wariancja porcentu wykrytych") logger.info(matchRateVariance) logger.info("# ------------------- KONIEC --------------------") return tuple