2011-12-24 2 views
0

У меня есть следующая проблема. У меня есть набор данных, который имеет начало (STRTTIME) и время окончания (ENDTIME) поездки в военном формате времени. Я хочу выяснить количество поездок за каждый 15-минутный прирост времени. Моя цель - определить количество поездок, которые происходят в каждый 15-минутный период времени, начиная с 0000 до 2359 (96 временных интервалов). Я могу написать 96 фиктивных переменных в excel и сделать это, но я предпочел бы иметь некоторый код в R или Python (я изучаю оба, так что мои знания являются рудиментарными). Я могу поместить счетчик, а затем увеличить, но я не уверен, как иметь дело с двумя переменными времени и обнаруживать, что я нахожусь в зависании. Мой пример ниже. Here is some sample data (в формате CSV).Код для определения числа 15-минутных периодов

  1. Предположим, что поездка начинается в 0805 и заканчивается в 0840, то каждый 15-минутный период будут иметь следующие значения:
    • 0000-0015 - 0
    • 0015-0030 - 0
    • ....
    • 0800-0815 - 2/3
    • 0815-0830 - 1
    • 0830-0845 - 2/3
    • 0845-09 00 - 0
    • ...
    • 2330-2345 - 0
    • 2345-2400 - 0
  2. Пусть другая поездка начинается в 0810 и заканчивается в 0850, то каждый 15-минутный период будет иметь следующий значения:
    • 0000-0015 - 0
    • 0015-0030 - 0
    • ....
    • 0800-0815 - 1/3
    • 0815-0830 - 1
    • 0830-0845 - 1
    • 0845-0900 - 1/3
    • ...
    • 2330-2345 - 0
    • 2345-2400 - 0
  3. После обработки этих двух записей значения в фиктивных полях за 15 минут будут следующими (т.е. она увеличивается его значением поля в предыдущей записи):
    • 0000-0015 - 0
    • 0015-0030 - 0
    • ....
    • 0800-0815 - 1
    • 0815-0830 - 2
    • 0830-0845 - 5/3
    • 0845-0900 - 1/3
    • ...
    • 2330-2345 - 0
    • 2345-2400 - 0

Любой код, чтобы сделать это очень ценится.

+0

Почему 805 2/3? Разумеется, это будет 1/3 из 15-минутного временного интервала 800-815? – BeRecursive

+0

Ну, где именно вы застряли? Вы узнали о модуле CSV и знаете, как читать CSV-файл?Вы узнали о модулях time/datetime и знаете, как создавать время и делать расчеты времени? Знаете ли вы, что, вероятно, неплохо хранить значения как плавающие из-за проблем округления? Вы знаете о списках и/или диктофонах? –

+0

@BeRecursive: поездка начинается с 0805 и продолжается до 08:15, поэтому она занимает 2/3 от 15-минутного временного интервала между 08:00 и 08:15. –

ответ

4

Поскольку ответа еще нет, я добавлю для этого один. Я чувствую, что решение может быть немного более элегантным, чем python, но это вопрос вкуса.

Во-первых, мы должны читать данные:

data <- read.csv('sample_data.csv') 

Затем я хотел бы преобразовать раз десятичном формате. Поэтому я использую час и минимум, а не военный формат. Однако это не было бы проблемой, так как вы всегда могли бы преобразовывать значения с помощью простой целочисленной арифметики.

data <- cbind(data, start = data$STARTHR + data$STARTMIN/60, end= data$ENDHR + data$ENDMIN/60) 

Теперь генерировать временные интервалы (которые мы будем выявлять их STARTTIME)

intervals <- seq(0, 23.75, by=0.25) 

Эта часть немного сложнее ... Сначала мы проверим, который срабатывает позже, чем конец нашего интервального конца , Все эти поездки мы Назначьте 1, поездки, которые заканчиваются до нашего интервала мы назначим 0. Если поездка заканчивается в течение интервала, мы будем использовать назначить соответствующую фракцию между 0 и 1.

endvalues <- (pmax(pmin(outer(data$end, intervals, FUN="-"), 0.25), 0)/0.25) 

Примечания использование внешнего. Здесь функция «-» (вычитание) используется для всех комбинаций конечных точек и вектора интервалов. Все остальные операции являются элементарными. Я предлагаю вам просто протестировать операцию шаг за шагом, тогда должно быть очевидно, что сделано.

Аналогично, мы будем делать это с помощью начальных интервалов, но теперь мы будем использовать отрицательные знаки.

startvalues <- (pmax(pmin(-outer(data$start, intervals, FUN="-"), 0), -0.25)/0.25) 

Это позволяет сформировать матрицу, которая имеет 1 всякий раз, когда интервал полностью находится в пределах поездки:

resultmatrix <- endvalues + startvalues 

Наконец, мы можем подвести итог по всем поездкам и получить количество поездок в пределах каждого интервала:

intervalcount <- apply(resultmatrix, 2, sum) 
+0

Это отлично работает с моим набором данных. Благодарю. – Krishnan

3

Поскольку вы пытаетесь создать гистограмму, вы эффективно решаете общую проблему «биннинга данных», но несколько иначе!

Самое легкое решение - сначала создать словарь индексов от 0 до 95 (96 фрагментов, как вы упомянули). Каждый из них представляет собой 15-минутный блок времени.

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

import csv 
spamReader = csv.reader(open('sample_data.csv', 'rb'), delimiter=',') 

histogram = dict() 

def toMinutes(militaryTime): 
    if type(militaryTime) != str: 
     raise ValueError("requires string as arg") 
    hours = int(militaryTime[:2]) 
    mins = int(militaryTime[2:]) 
    return 60*hours + mins 

for record in spamReader: 
    if record[0] == 'STRTTIME': 
     continue #skip first record which contains headers 
    startTime = toMinutes(record[0]) #must convert militarytime to minutes 
    endTime = toMinutes(record[1]) 

    startIndex = int(int(startTime)/15.0) #int division in python 3.0 and 2.X 
    endIndex = int(int(endTime)/15) #is handled different, this unifies the two 

    for i in range(startIndex,endIndex+1): 
     valAd = 1 
     if i == startIndex: 
      valAd = 1-((startTime-(15*i))/15.0) 
     if i == endIndex: 
      valAd = ((endTime-(15*i))/15.0) #opposite boundary condition 
     histogram[i] = histogram.get(i,0) + valAd 
for key,val in histogram.items(): 
    print key,val 
''' 
output from your example csv, in minutes, which can easily be converted to militaryTime 
41 0.666666666667 
42 1 
43 0.333333333333 
46 0.333333333333 
47 1 
48 1.8 
49 0.666666666667 
50 1.26666666667 
51 1 
52 1 
53 1 
54 1 
55 1 
56 1 
57 1 
58 0.666666666667 
59 1.33333333333 
60 1.0 
61 1 
62 1 
63 1 
64 1 
65 1 
66 0.333333333333 
67 0.266666666667 
68 1 
69 1.8 
70 0.0 
72 1.0 
73 1 
74 2.0 
75 1.33333333333 
76 1 
77 1 
78 1 
79 1 
80 0.0 
94 1.0 
95 0.333333333333 
360 1.0 
361 1 
362 1 
363 1 
364 1 
365 1 
366 1 
367 1 
368 1 
369 1 
370 1 
371 1 
372 0.0 
''' 
+0

Спасибо за код. Извините, что было не ясно о фракции из-за того, как я ее создал. Я хочу получить гистограмму, которая показывает количество поездок за каждый 15-минутный срез времени. Следовательно, необходимо сохранить вкладку дробных поездок. – Krishnan

+0

Это работает. Я просто должен убедиться, что длина военного времени составляет 4 карата. – Krishnan

0

я мог бы быть неправильное понимание фракций часть вопроса, как я воспринимаю это как способ для вас, чтобы определить, должен ли он засчитываться всем "I want to figure out the number of 15 minute time increments the trip is taking place". Если это то, что вы хотите, и, например, 10 минут не учитывается как приращение времени, то что-то вроде этого будет отлично работать для того, что я только что процитировал.

len([x for x in range(len(range(int('0000'), int('0215'), 15))) if x%7 < 4]) 
#outputs: 9 

В принципе, так как это в военное время, вы можете бросить его как междунар и создать диапазон, принимая 15 шагов. Это создаст список, в котором вы хотите взять 4 элемента, отбросить 3 элемента, принять 4 и так далее. Поэтому я беру длину и перебираю новый диапазон объектов для нормализации до 0,1,2,3,4 и т. Д. И использую x% 7 < 4, чтобы сделать именно это.

Вы можете создать функцию для передачи в двух строках. Итак, в приведенном выше случае, если вы изменили '0000' на '0010', он вернет 8, так как вы просто разрезаете 10 минут в один из 15-минутных периодов.

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

+0

Спасибо за указатель. Поскольку я написал выше извинения, что это не было ясно о фракции из-за того, как я создал его, и я отредактирую его правильно. Я хочу получить гистограмму, которая показывает количество поездок за каждый 15-минутный срез времени. Следовательно, необходимо сохранить вкладку дробных поездок. – Krishnan

+0

ah ok, теперь я понимаю – dskinner

4

Позвольте мне представить решение точно так, как вы представляли

  1. Первый Lets Определение 15 мин Время Ranges. Itertools.product используется для создания всего диапазона времени, отформатированного с помощью datetime strftime после преобразования с time.

    timeset=[datetime.time(h,m).strftime("%H%M") for h,m in itertools.product(xrange(0,24),xrange(0,60,15))]+['2400'] 
    >>> timeset 
    ['0000', '0015', '0030', '0045', '0100', '0115', '0130', '0145', '0200', '0215', '0230', '0245', '0300', '0315', '0330', '0345', '0400', '0415', '0430', '0445', '0500', '0515', '0530', '0545', '0600', '0615', '0630', '0645', '0700', '0715', '0730', '0745', '0800', '0815', '0830', '0845', '0900', '0915', '0930', '0945', '1000', '1015', '1030', '1045', '1100', '1115', '1130', '1145', '1200', '1215', '1230', '1245', '1300', '1315', '1330', '1345', '1400', '1415', '1430', '1445', '1500', '1515', '1530', '1545', '1600', '1615', '1630', '1645', '1700', '1715', '1730', '1745', '1800', '1815', '1830', '1845', '1900', '1915', '1930', '1945', '2000', '2015', '2030', '2045', '2100', '2115', '2130', '2145', '2200', '2215', '2230', '2245', '2300', '2315', '2330', '2345', '2400'] 
    
  2. Позволяет также определить хронометрист списка той же длины, как timeset но инициализируется в ноль

    timekeeper=[0]*len(timeset) 
    
  3. Для простоты, вместо чтения из CSV, я определю кортеж с одни и те же данные, как ваш представленного XLS лист

    counter=[('1020','1050'),('0900','0930'),('1830','2000'),('2330','2350'),('1200','1202'),('1232','1234'),('1450','1635'),('1220','1440'),('0930','1205'),('1656','1730'),('1800','1850'),('1200','1210'),('1715','1727'),('1140','1215'),('1450','1500')] 
    
  4. следующая функция является основным процессором. Я использовал bisect, чтобы определить начальную и конечную временную последовательность.Я также использовал fraction, чтобы избежать плавающей точки и поддерживать формат, как показано в задаче

    def TimeCounter(timekeeper,timeset,(sttime,entime)): 
        st=bisect.bisect_left(timeset,sttime) 
        en=bisect.bisect_left(timeset,entime) 
        timekeeper[st]+=fractions.Fraction(int(timeset[st])-int(sttime),15) 
        timekeeper[en]+=fractions.Fraction(int(entime)-int(timeset[en-1]),15) 
        for i in xrange(st+1,en): 
         timekeeper[i]+=1 
    
  5. Наконец следующих два лайнера будет перебрать предоставленные данные счетчика и вызовы Timecounter для каждой последовательности данных для обновления хронометриста

    for c in counter: 
        TimeCounter(timekeeper,timeset,c) 
    
  6. Заключительное о/р выглядит примерно так

    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Fraction(0, 1), 2, Fraction(2, 1), 2, 2, 2, Fraction(10, 3), 4, Fraction(8, 3), 2, 2, Fraction(8, 3), Fraction(4, 1), Fraction(64, 15), Fraction(4, 3), Fraction(64, 15), 2, 2, 2, 2, 2, 2, 2, Fraction(4, 3), Fraction(62, 3), 2, 2, 2, 2, 2, 2, Fraction(2, 3), Fraction(88, 15), Fraction(2, 1), Fraction(18, 5), 0, Fraction(0, 1), 2, Fraction(2, 1), 4, Fraction(8, 3), 2, 2, 2, Fraction(22, 3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Fraction(0, 1), 2, Fraction(2, 3)] 
    
  7. Наконец Если вы wan't печатать данные точно в изображенном формате, вы можете использовать этот код

    for i in xrange(0,len(timeset)-1): 
        print '-'.join([timeset[i],timeset[i+1],str(timekeeper[i+1])]) 
    

А вот пример о/р от окончательных формулировок дисплея

1015-1030-10/3 
1030-1045-4 
1045-1100-8/3 
1100-1115-2 
1115-1130-2 
1130-1145-8/3 
1145-1200-4 
1200-1215-64/15 
1215-1230-4/3 
1230-1245-64/15 
+0

Благодарим за код и объяснение. Я решил использовать это, поскольку он работает точно так, как я хочу. – Krishnan

+0

Спасибо за код, но я решил пойти с кодом R, так как у меня возникли проблемы с чтением данных из CSV с другими переменными в нем. Таким образом, с моей стороны нужно сделать больше работы, чтобы понять, как питон читает файлы и т. Д. – Krishnan

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