def radius_of_gyration(positions, user): """ The radius of gyration. The radius of gyration is the *equivalent distance* of the mass from the center of gravity, for all visited places [GON2008]_ None is returned if there are no (lat, lon) positions for where the user has been. .. [GON2008] Gonzalez, M. C., Hidalgo, C. A., & Barabasi, A. L. (2008). Understanding individual human mobility patterns. Nature, 453(7196), 779-782. """ d = Counter(p._get_location(user) for p in positions if p._get_location(user) is not None) sum_weights = sum(d.values()) positions = d.keys() # Unique positions if len(positions) == 0: return None barycenter = [0, 0] for pos, t in d.items(): barycenter[0] += pos[0] * t barycenter[1] += pos[1] * t barycenter[0] /= sum_weights barycenter[1] /= sum_weights r = 0. for pos, t in d.items(): r += float(t) / sum_weights * great_circle_distance(barycenter, pos) ** 2 r += float(t) / sum_weights * great_circle_distance(barycenter, pos) ** 2 return math.sqrt(r)
def number_of_contacts_xpercent_interactions(records, percentage=0.8): """ The number of user's contacts that account for 80% of its interactions. """ user_count = Counter(r.correspondent_id for r in records) target = int(math.floor(sum(user_count.values()) * percentage)) user_sort = sorted(user_count.keys(), key=lambda x: user_count[x]) while target > 0 and len(user_sort) > 0: user_id = user_sort.pop() target -= user_count[user_id] return len(user_count) - len(user_sort)
def frequent_locations(positions, percentage=0.8): """ The number of location that account for 80% of the locations where the user was. """ location_count = Counter(map(str, positions)) target = int(math.floor(sum(location_count.values()) * percentage)) location_sort = sorted(location_count.keys(), key=lambda x: location_count[x]) while target > 0 and len(location_sort) > 0: location_id = location_sort.pop() target -= location_count[location_id] return len(location_count) - len(location_sort)
def recompute_home(self): """ Return the antenna where the user spends most of his time at night. None is returned if there are no candidates for a home antenna """ if self.night_start < self.night_end: night_filter = lambda r: self.night_end > r.datetime.time() > self.night_start else: night_filter = lambda r: not(self.night_end < r.datetime.time() < self.night_start) # Bin positions by chunks of 30 minutes candidates = list(_binning(filter(night_filter, self._records))) if len(candidates) == 0: self.home = None self.has_home = False return None else: self.home = Counter(candidates).most_common()[0][0] self.has_home = True return self.home
def interactions_per_contact(records): """ The number of interactions a user had with each of its contacts. """ counter = Counter(r.correspondent_id for r in records) return summary_stats(counter.values(), 1)
def entropy_of_contacts(records): """ The entropy of the user's contacts. """ counter = Counter(r.correspondent_id for r in records) return entropy(counter.values())
def number_of_contacts(records, more=0): """ The number of contacts the user interacted with. """ counter = Counter(r.correspondent_id for r in records) return sum(1 for d in counter.values() if d > more)
def entropy_places(positions): """ The entropy of visited antennas. """ counter = Counter(p for p in positions) return entropy(counter.values())