2013-09-15 3 views
0

Привет, я пишу скрипт python для генерации ежемесячных и ежедневных посещений веб-страниц. Входной файл:Python скрипт не работает по мере необходимости

ArticleName Date  Hour Count/Visit 
Aa 20130601 10000 1 
Aa 20130601 10000 1 
Ew 20130601 10000 1 
H 20130601 10000 2 
H 20130602 10000 1 
R 20130601 20000 2 
R 20130602 10000 1 
Ra 20130601 0 1 
Ra 20130601 10000 2 
Ra 20130602 10000 1 
Ram 20130601 0 2 
Ram 20130601 10000 3 
Ram 20130602 10000 4 
Re 20130601 20000 1 
Re 20130602 10000 3 
Rz 20130602 10000 1 

Мне нужно посчитать общее количество ежемесячных и ежедневных просмотров страниц каждой страницы.

Выход:

ArticleName Date  DailyView MonthlyView 
Aa 20130601 2 2 
Ew 20130601 1 1 
H 20130601 2 2 
H 20130602 1 3 
R 20130601 2 2 
R 20130602 1 4 
Ra 20130601 5 5 
Ra 20130602 1 6 
Ram 20130601 5 5 
Ram 20130602 4 9 
Re 20130601 1 1 
Re 20130602 3 4 
Rz 20130602 1 1 

Мой сценарий:

#!/usr/bin/python 

import sys 

last_date = 20130601 
last_hour = 0 
last_count = 0 
last_article = None 
monthly_count = 0 
daily_count = 0 

for line in sys.stdin: 
    article, date, hour, count = line.split() 
    count = int(count) 
    date = int(date) 
    hour = int(hour) 

    #Articles match and date match 
    if last_article == article and last_date == date: 
     daily_count = count+last_count 
     monthly_count = count+last_count 
     # print '%s\t%s\t%s\t%s' % (article, date, daily_count, monthly_count) 
    #Article match but date doesn't match 
    if last_article == article and last_date != date: 
      monthly_count = count 
      daily_count=count 
      print '%s\t%s\t%s\t%s' % (article, date, daily_count, monthly_count) 


    #Article doesn't match 
    if last_article != article: 
      last_article = article 
      last_count = count 
      monthly_count = count 
      daily_count=count 
      last_date = date 
      print '%s\t%s\t%s\t%s' % (article, date, daily_count, monthly_count) 

Я могу получить большую часть продукции, но мой выход неправильно для двух условий: 1. Не удалось получить путь суммировать ItemName, если ArticleName и ArticleDate являются одинаковыми. Например, этот сценарий дает выходные данные для строки Ra: Ra 20130601 1 1 Ra 20130601 3 3 Ra 20130602 1 1 Итак, в конце Ra должно печатать 1 + 3 + 1 = 5 в качестве итогового общего месячного счета вместо 1.

  1. Так как я показываю в третьем условии, если все статьи, которые не равны последней статье, я получаю значение статьи с тем же именем и датой статьи дважды. Например: Ra 20130601 1 1 не должны были быть напечатаны. Кто-нибудь знает, как исправить это? Сообщите мне, если вам нужна дополнительная информация.
+0

Все данные предназначены для Jun2013, но все статьи отличаются. Мне нужно узнать, сколько раз каждую статью посещали ежедневно и ежемесячно. – CtrlV

+0

Я понял. Они являются совокупным счетом? правильно? – falsetru

+1

'R 20130602 1 4' должен быть' R 20130602 1 3'? – falsetru

ответ

1

Попробуйте следующее:

import itertools 
import operator 
import sys 

lines = (line.split() for line in sys.stdin) 
prev_name, prev_month = '', '99999999' 
month_view = 0 
for (name,date), grp in itertools.groupby(lines, key=operator.itemgetter(0,1)): 
    view = sum(int(row[-1]) for row in grp) 
    if prev_name == name and date.startswith(prev_month): 
     month_view += view 
    else: 
     prev_name = name 
     prev_month = date[:6] 
     month_view = view 
    print '{}\t{}\t{}\t{}'.format(name, date, view, month_view) 

Используется itertools.groupby, operator.itemgetter.

Выход отличается:

Aa  20130601  2  2 
Ew  20130601  1  1 
H  20130601  2  2 
H  20130602  1  3 
R  20130601  2  2 
R  20130602  1  3 
Ra  20130601  3  3 
Ra  20130602  1  4 
Ram  20130601  5  5 
Ram  20130602  4  9 
Re  20130601  1  1 
Re  20130602  3  4 
Rz  20130602  1  1 
+0

Спасибо @falsetru. Проблема в понимании того, что делает этот код в python: для (имя, дата), grp в itertools.groupby (строки, key = operator.itemgetter (0,2)): view = sum (int (row [-1 ]) для строки в grp) Я могу понять, что я получаю два значения: имя и дата из строк, которые являются 1-м и третьим значением в строке и остальной частью строки как grp. Я прав? Также во втором представлении строки суммируется, когда [-1] строка в grp строки? Если да, то какая -1 строка указывает, начинается ли строка с -1 в Python – CtrlV

+0

@CtrlV, 'xs [-1]' получает последнее значение 'xs'. – falsetru

+0

@CtrlV, я использовал 'groupby (lines, key = operator.itemgetter (0,1))' not '0,2' ..: Он группирует строки по первым, вторым полям. (ArticleName, Date). Для каждого цикла, 'name',' date' reference 'ArticleName, Date'. И ссылочный итератор 'grp', который дает сгруппированные строки. – falsetru

0

Простым способом сделать это будет ИМХО, чтобы создать двойной словарь с именем страницы в качестве ключа, а значение - это словарь с даты на количество просмотров, перебрать список и построить словарь, а затем перебрать словарь для каждой страницы и подсчет количества страниц за каждый месяц.

1

Лучший способ добиться того, что вы хотите использовать карту - уменьшить функции, найденные в itertools: http://docs.python.org/2/howto/functional.html версия

import itertools 
from itertools import groupby 
from itertools import dropwhile 
import sys 
import datetime 

# Convert list of words found in one line into 
# a tuple consisting of a name, date/time and number of visits 
def get_record(w): 
    name = w[0] 
    date = datetime.datetime.strptime((w[1] + ('%0*d' % (6, int(w[2])))), "%Y%m%d%H%M%S") 
    visits = int(w[3]) 
    return (name, date, visits) 

# Takes a tuple representing a single record and returns a tuple 
# consisting of a name, year and month on which the records will 
# be grouped. 
def get_key_by_month((name, date, visits)): 
    return (name, date.year, date.month) 

# Takes a tuple representing a single record and returns a tuple 
# consisting of a name, year, month and day on which the records will 
# be grouped. 
def get_key_by_day((name, date, visits)): 
    return (name, date.year, date.month, date.day) 

# Get a list containing lines, each line containing 
# a list of words, skipping the first line 
words = (line.split() for line in sys.stdin) 
words = dropwhile(lambda x: x[0]<1, enumerate(words)) 
words = map(lambda x: x[1], words) 

# Convert to tuples containg name, date/time and count 
records = list(get_record(w) for w in words) 

# Group by name, month 
groups = groupby(records, get_key_by_month) 

# Sum visits in each group 
print('Visits per month') 
for (name, year, month), g in groups: 
    visits = sum(map(lambda (name,date,visits): visits, g)) 
    print name, year, month, visits 

# Group by name, day 
groups = groupby(records, get_key_by_day) 

# Sum visits in each group 
print ('\nVisits per day') 
for (name, year, month, day), g in groups: 
    visits = sum(map(lambda (name,date,visits): visits, g)) 
    print name, year, month, day, visits 

Python 3 из приведенного выше кода :

import itertools 
from itertools import groupby 
from itertools import dropwhile 
import sys 
import datetime 

# Convert list of words found in one line into 
# a tuple consisting of a name, date/time and number of visits 
def get_record(w): 
    name = w[0] 
    date = datetime.datetime.strptime((w[1] + ('%0*d' % (6, int(w[2])))), "%Y%m%d%H%M%S") 
    visits = int(w[3]) 
    return (name, date, visits) 

# Takes a tuple representing a single record and returns a tuple 
# consisting of a name, year and month on which the records will 
# be grouped. 
def get_key_by_month(rec): 
    return (rec[0], rec[1].year, rec[1].month) 

# Takes a tuple representing a single record and returns a tuple 
# consisting of a name, year, month and day on which the records will 
# be grouped. 
def get_key_by_day(rec): 
    return (rec[0], rec[1].year, rec[1].month, rec[1].day) 

# Get a list containing lines, each line containing 
# a list of words, skipping the first line 
words = (line.split() for line in sys.stdin) 
words = dropwhile(lambda x: x[0]<1, enumerate(words)) 
words = map(lambda x: x[1], words) 

# Convert to tuples containg name, date/time and count 
records = list(get_record(w) for w in words) 

# Group by name, month 
groups = groupby(records, get_key_by_month) 

# Sum visits in each group 
print('Visits per month') 
for (name, year, month), g in groups: 
    visits = sum(map(lambda rec: rec[2], g)) 
    print(name, year, month, visits) 

# Group by name, day 
groups = groupby(records, get_key_by_day) 

# Sum visits in each group 
print ('\nVisits per day') 
for (name, year, month, day), g in groups: 
    visits = sum(map(lambda rec: rec[2], g)) 
    print(name, year, month, day, visits) 
+0

Этот код можно сократить с помощью лямбда-выражений и переместить вызов в groupby() непосредственно в цикле for. Я предпочел делать что-то шаг за шагом, чтобы ясность и легкость отладки. – Tarik

+0

Спасибо @Tarik Я многому научился от вашего способа кодирования! – CtrlV

+0

Улучшен код, создавая итератор, который пропускает строку заголовка вместо создания списка и выскакивает первый элемент, в результате чего все данные сохраняются в памяти. – Tarik

Смежные вопросы