Source code for okcupyd.statistics

import itertools
import numbers

from . import util
from .attractiveness_finder import AttractivenessFinder


[docs]class Statistics(object): def __init__(self, user, message_threads=None, filters=(), attractiveness_finder=None): self._user = user self._message_threads = message_threads or set(itertools.chain(user.inbox, user.outbox)) self._filters = filters self._attractiveness_finder = attractiveness_finder or AttractivenessFinder() def _thread_matches(self, message_thread): return all(f(message_thread) for f in self._filters) @util.cached_property def threads(self): return set(mt for mt in self._message_threads if self._thread_matches(mt)) @util.cached_property def has_messages(self): return self.with_filters(lambda mt: mt.has_messages) @util.cached_property def has_response(self): return self.with_filters(lambda mt: mt.got_response) @util.cached_property def no_responses(self): return self.with_filters(lambda mt: not mt.got_response) @util.cached_property def initiated(self): return self.with_filters(lambda mt: mt.initiator == self._user.profile) @util.cached_property def received(self): return self.with_filters(lambda mt: mt.initiator != self._user.profile) @util.cached_property def has_attractiveness(self): return self.with_filters(lambda mt: self._attractiveness_finder.find_attractiveness( mt.correspondent) is not None)
[docs] def time_filter(self, min_date=None, max_date=None): def _time_filter(thread): if min_date and min_date > thread.date: return False if max_date and max_date < thread.date: return False return True return self.with_filters(_time_filter)
[docs] def attractiveness_filter(self, attractiveness_finder=None, min_attractiveness=0, max_attractiveness=10000): attractiveness_finder = attractiveness_finder or self._attractiveness_finder def _attractiveness_filter(thread): attractiveness = attractiveness_finder.find_attractiveness( thread.correspondent ) return (isinstance(attractiveness, numbers.Number) and min_attractiveness <= attractiveness <= max_attractiveness) return self.with_filters(_attractiveness_filter)
[docs] def with_filters(self, *filters, **kwargs): message_threads = self.threads \ if kwargs.get('apply_filters_immediately', True) \ else self._message_threads return type(self)(self._user, message_threads, self._filters + filters, attractiveness_finder=self._attractiveness_finder)
@property def count(self): return len(self.threads) @property def response_rate(self): return float(self.has_response.count)/self.count def _average(self, function): return sum(map(function, self.threads))/self.count @property def average_first_message_length(self): return self._average(lambda thread: len(thread.messages[0].content)) @property def average_conversation_length(self): return self._average(lambda thread: thread.message_count) def _average_attractiveness(self, attractiveness_finder=None): attractiveness_finder = attractiveness_finder or self._attractiveness_finder return self.has_attractiveness._average(lambda thread: ( attractiveness_finder.find_attractiveness( thread.correspondent )) ) @property def average_attractiveness(self): return self._average_attractiveness() @property def portion_initiated(self): return self.initiated.count/self.count @property def portion_received(self): return 1 - self.portion_initiated