def end_users(self, stat: Dict[str, Any]) -> None: assert self.stat for step in self._ratings: with open(os.path.join(self.stat.destination, 'users_ratings_{}.csv'.format(step)), 'w', encoding='utf-8') as fp: fp.write(utils.csvline('Рейтинг', 'Число пользователей')) step_vote = min(self._ratings[step]) vmax = max(self._ratings[step]) while step_vote <= vmax: count = self._ratings[step].get(step_vote, 0) x1 = '{:.2f}'.format(step_vote) x2 = '{:.2f}'.format(round(step_vote + (step - 0.01), 2)) fp.write(utils.csvline(x1 + ' – ' + x2, count)) step_vote += step with open(os.path.join(self.stat.destination, 'users_ratings_zero.txt'), 'w', encoding='utf-8') as fp: fp.write('{}\n'.format(self._zero))
def stop(self) -> None: assert self.stat min_rating = 0 max_rating = 0 for votes_dict in self._stat.values(): min_rating = min(min(votes_dict), min_rating) max_rating = max(max(votes_dict), max_rating) header = ['Рейтинг', 'За всё время'] for year in sorted(self._stat): header.append('{} год'.format(year)) with open(os.path.join(self.stat.destination, 'posts_ratings.csv'), 'w', encoding='utf-8') as fp: fp.write(utils.csvline(*header)) for vote in range(min_rating, max_rating + 1): line = [vote, 0] for year in sorted(self._stat): line.append(self._stat[year].get(vote, 0)) line[1] += line[-1] fp.write(utils.csvline(*line)) super().stop()
def end_users(self, stat: Dict[str, Any]) -> None: assert self.stat with open(os.path.join(self.stat.destination, 'birthdays.csv'), 'w', encoding='utf-8') as fp: fp.write(utils.csvline('День рождения', 'Число пользователей')) for day, user_ids in sorted(self._birthdays.items(), key=lambda x: len(x[1]), reverse=True): fp.write(utils.csvline('{:02d}.{:02d}'.format(*day), len(user_ids)))
def stop(self) -> None: assert self.stat # Считаем статистику за всё время... counts_all = [0] * 24 days_all = 0 # ...и по годам... counts_year = {} # type: Dict[int, List[int]] days_year = {} # type: Dict[int, int] # ...в одном цикле for (year, monn), stat in self._counts.items(): days = self._days[(year, monn)] if year not in counts_year: counts_year[year] = [0] * 24 days_year[year] = 0 days_all += days days_year[year] += days for hour, cnt in enumerate(stat): counts_all[hour] += cnt counts_year[year][hour] += cnt last_months = sorted(self._counts)[-2:] # Собираем CSV-заголовок header = ['Час ({})'.format(str(self.stat.timezone)), 'За всё время'] for year in sorted(counts_year): header.append('{} год'.format(year)) for mon in last_months: header.append('{:04d}-{:02d}'.format(*mon)) with open(os.path.join(self.stat.destination, 'posts_counts_avg.csv'), 'w', encoding='utf-8') as fp: fp.write(utils.csvline(*header)) for hour in range(24): line = [hour] # type: List[Any] # За всё время line.append('{:.2f}'.format(counts_all[hour] / (days_all or 1))) # И по годам for year in sorted(counts_year): line.append('{:.2f}'.format(counts_year[year][hour] / (days_year.get(year) or 1))) # И за два последних месяца for mon in last_months: line.append('{:.2f}'.format(self._counts[mon][hour] / (self._days.get(mon) or 1))) fp.write(utils.csvline(*line)) super().stop()
def start(self, stat: TabunStat, min_date: Optional[datetime] = None, max_date: Optional[datetime] = None) -> None: super().start(stat, min_date, max_date) assert self.stat self._fp = open(os.path.join(self.stat.destination, 'posts_counts.csv'), 'w', encoding='utf-8') self._fp_sum = open(os.path.join(self.stat.destination, 'posts_counts_sum.csv'), 'w', encoding='utf-8') self._fp_perc = open(os.path.join(self.stat.destination, 'posts_counts_perc.csv'), 'w', encoding='utf-8') # Применяем часовой пояс к периоду self.period_end = self._append_days(self.period_begin) header = ['Первый день недели'] + self._labels header_csv = utils.csvline(*header) self._fp.write(header_csv) self._fp_sum.write(header_csv) self._fp_perc.write(utils.csvline( *header[:-1])) # В процентах комменты из лички не учитываем
def save_stat(self, filename: str, stat_posts: Dict[int, int], stat_comments: Dict[int, int]) -> None: assert self.stat stat = {} # type: Dict[int, List[int]] for user_id, count in stat_posts.items(): if user_id not in stat: stat[user_id] = [0, 0] stat[user_id][0] = count for user_id, count in stat_comments.items(): if user_id not in stat: stat[user_id] = [0, 0] stat[user_id][1] = count items = sorted(stat.items(), key=lambda x: x[1][0] + x[1][1], reverse=True) with open(os.path.join(self.stat.destination, filename), 'w', encoding='utf-8') as fp: fp.write( utils.csvline('ID юзера', 'Пользователь', 'Сколько постов', 'Сколько комментов')) for user_id, (posts_count, comments_count) in items: fp.write( utils.csvline( user_id, self.stat.source.get_username_by_user_id(user_id), posts_count, comments_count))
def stop(self) -> None: assert self.stat with open(os.path.join(self.stat.destination, 'nicknames.csv'), 'w', encoding='utf-8') as fp: fp.write(utils.csvline('Первая буква ника', 'Число пользователей')) for c, user_ids in sorted(self._letters.items(), key=lambda x: len(x[1]), reverse=True): fp.write(utils.csvline(c, len(user_ids))) super().stop()
def stop(self) -> None: assert self.stat with open(os.path.join(self.stat.destination, 'dices.csv'), 'w', encoding='utf-8') as fp: fp.write( utils.csvline('ID юзера', 'Пользователь', 'Сколько публикаций с дайсами', 'Сколько раз брошены дайсы')) for user_id, (msgs_count, dices_count) in sorted(self._dices.items(), key=lambda x: x[1][0], reverse=True): fp.write( utils.csvline( user_id, self.stat.source.get_username_by_user_id(user_id), msgs_count, dices_count)) super().stop()
def _flush_stat(self) -> None: assert self.stat period_begin_local = utils.apply_tzinfo(self.period_begin, self.stat.timezone) # Собираем три разные строки для трёх файлов line = [period_begin_local.strftime('%Y-%m-%d')] # type: List[Any] line_sum = line[:] # type: List[Any] line_perc = line[:] # type: List[Any] # Высчитываем, что такое 100% all_exist_count = sum(self._stat) # И собираем в строки данные по каждой категории cnt_sum = 0 for cnt in self._stat: # В простой файл просто пишем число как есть line.append(cnt) # В файле с суммами используем складывание слева направо для более простого рисования графиков cnt_sum += cnt line_sum.append(cnt_sum) # Проценты тоже суммируем для удобства рисования графиков percent = 0.0 if all_exist_count <= 0 else (cnt_sum * 100.0 / all_exist_count) line_perc.append('{:.2f}'.format(percent)) # Пишем в файлы assert self._fp self._fp.write(utils.csvline(*line)) assert self._fp_sum self._fp_sum.write(utils.csvline(*line_sum)) assert self._fp_perc self._fp_perc.write(utils.csvline(*line_perc)) # Обнуляем статистику для начала следующего периода self._stat = [0] * len(self._labels) # Высчитываем следующий период self.period_begin = self.period_end self.period_end = self._append_days(self.period_begin)
def stop(self) -> None: assert self.stat with open(os.path.join(self.stat.destination, 'chars.csv'), 'w', encoding='utf-8') as fp: fp.write(utils.csvline('Символ', 'Сколько раз встретился')) for c, x in sorted(self._chars.items(), key=lambda x: [-x[1][0], x[1][1]]): cnt, created_at_unix = x # created_at = utils.apply_tzinfo( # datetime.utcfromtimestamp(created_at_unix), # self.stat.timezone # ) if c == '"': c = 'Кавычка' elif c == ',': c = 'Запятая' elif c == ' ': c = 'Пробел' elif c == '\u00a0': c = 'Неразр. пробел' elif c == '\t': c = 'Табуляция' elif c == '\n': c = 'Перенос строки' elif c == '\r': c = 'Возврат каретки' elif c.lower() in ('a', 'o', 'e', 'c', 'k', 'p', 'x', 'm') or c in ('B', 'T', 'H', 'y'): c = c + ' (англ.)' elif not c.strip(): c = repr(c) fp.write(utils.csvline(c, cnt)) super().stop()
def end_users(self, stat: Dict[str, Any]) -> None: assert self.stat if not self._stat: return day = min(self._stat) max_day = max(self._stat) with open(os.path.join(self.stat.destination, 'registrations.csv'), 'w', encoding='utf-8') as fp: fp.write( utils.csvline('Дата', 'Новые пользователи', 'Всего пользователей', 'Всего с рейтингом больше -20', 'Всего с рейтингом больше +20')) all_users = 0 all_users_gte_minus20 = 0 all_users_gte_plus20 = 0 while day <= max_day: # Слава костылям if day not in self._stat and ( day.year < 2011 or day.year == 2011 and day.month < 8): day += timedelta(days=1) continue all_users += self._stat.get(day, 0) all_users_gte_minus20 += self._stat_gte_minus20.get(day, 0) all_users_gte_plus20 += self._stat_gte_plus20.get(day, 0) fp.write( utils.csvline(day, self._stat.get(day, 0), all_users, all_users_gte_minus20, all_users_gte_plus20)) day += timedelta(days=1)
def _flush_activity(self, item: Dict[str, Any]) -> None: stat = [str(self._last_day)] # type: List[Any] for period in self.periods: # Собираем все id за последние period дней all_users = set() # type: Set[int] for a, b in item['activity'][-period:]: all_users = all_users | a | b item['users_with_posts'] = item['users_with_posts'] | a item['users_with_comments'] = item['users_with_comments'] | b stat.append(len(all_users)) # И пишем собранные числа в статистику assert item['fp'] item['fp'].write(utils.csvline(*stat))
def stop(self) -> None: assert self.stat with open(os.path.join(self.stat.destination, 'images.csv'), 'w', encoding='utf-8') as fp: fp.write( utils.csvline('Картинка', 'Первое исп-е', 'Первое исп-е на внешке', 'Последнее исп-е', 'Последнее исп-е на внешке', 'Сколько раз', 'Сколько раз на внешке')) for img in self._images_list: data = self._stat[img] fp.write( utils.csvline(img, data['first_date'], data['first_public_date'] or '', data['last_date'], data['last_public_date'] or '', data['count'], data['public_count'])) with open(os.path.join(self.stat.destination, 'images_hosts.csv'), 'w', encoding='utf-8') as fp: fp.write( utils.csvline('Хост', 'Число ссылок', 'Число использований')) items = sorted(self._hosts.items(), key=lambda x: x[1][1], reverse=True) for h, c in items: assert c[1] >= c[0] fp.write(utils.csvline(h, c[0], c[1])) with open(os.path.join(self.stat.destination, 'images_hosts2.csv'), 'w', encoding='utf-8') as fp: fp.write( utils.csvline('Хост', 'Число ссылок', 'Число использований')) items = sorted(self._hosts2.items(), key=lambda x: x[1][1], reverse=True) for h, c in items: assert c[1] >= c[0] fp.write(utils.csvline(h, c[0], c[1])) super().stop()
def start(self, stat: TabunStat, min_date: Optional[datetime] = None, max_date: Optional[datetime] = None) -> None: super().start(stat, min_date, max_date) assert self.stat header = ['Дата'] for period in self.periods: if period == 1: header.append('Активны в этот день') else: header.append('Активны в последние {} дней'.format(period)) for rating, item in self._ratings.items(): filename = 'activity.csv' if rating is not None: filename = 'activity_{:.2f}.csv'.format(rating) item['fp'] = open(os.path.join(self.stat.destination, filename), 'w', encoding='utf-8') item['fp'].write(utils.csvline(*header))
def stop(self) -> None: assert self.stat with open(os.path.join(self.stat.destination, 'words.csv'), 'w', encoding='utf-8') as fp: fp.write( utils.csvline('Слово', 'Первое исп-е', 'Первое исп-е на внешке', 'Последнее исп-е', 'Последнее исп-е на внешке', 'Сколько раз', 'Сколько раз на внешке', 'Сколько раз (без ботов)', 'Сколько раз на внешке (без ботов)', 'Сколько юзеров юзали', 'Кто юзал', 'Сколько юзеров юзали на внешке', 'Кто юзал на внешке')) for word in self._words_list: data = self._stat[word[:2]][word] fp.write( utils.csvline( word, data['first_date'], data['first_public_date'] or '', data['last_date'], data['last_public_date'] or '', data['count'], data['public_count'], data['nobots_count'], data['public_nobots_count'], len(data['users']), '; '.join(sorted(data['users'])) if len(data['users']) < 20 else '', len(data['public_users']), '; '.join(sorted(data['public_users'])) if len(data['public_users']) < 20 else '', )) with open(os.path.join(self.stat.destination, 'avgstats.txt'), 'w', encoding='utf-8') as fp: fp.write( 'Средняя длина поста: {} слов, {} символов, {} байт\n'.format( int(self._post_len_words[0] / self._post_len_words[1]) if self._post_len_words[1] != 0 else 0, int(self._post_len_chars[0] / self._post_len_chars[1]) if self._post_len_chars[1] != 0 else 0, int(self._post_len_bytes[0] / self._post_len_bytes[1]) if self._post_len_bytes[1] != 0 else 0, )) fp.write('Средняя длина коммента: {} слов, {} символов, {} байт\n'. format( int(self._comment_len_words[0] / self._comment_len_words[1]) if self._comment_len_words[1] != 0 else 0, int(self._comment_len_chars[0] / self._comment_len_chars[1]) if self._comment_len_chars[1] != 0 else 0, int(self._comment_len_bytes[0] / self._comment_len_bytes[1]) if self._comment_len_bytes[1] != 0 else 0, )) fp.write('Комментов без текста: {}\n'.format( self._comments_without_text)) super().stop()