Получить среднее время дня в SQLite из datetime - PullRequest
2 голосов
/ 23 февраля 2012

У меня есть время в SQLite в форме «2012-02-21 00: 00: 00.000000» и я хотел бы, чтобы среднее время дня вместе.Даты не имеют значения - просто времена.Так, например, если данные:

'2012-02-18 20:00:00.000000' 
'2012-02-19 21:00:00.000000' 
'2012-02-20 22:00:00.000000' 
'2012-02-21 23:00:00.000000' 

Среднее значение 20, 21, 22, 23 должно быть 21,5 или 21:30 (или 9:30 вечера в США).

Q1) Есть ли лучший способ сделать это в запросе SELECT в SQLite?

Но сложнее: что, если один или несколько из этих часов пересекают полночь?Они определенно будут в моем наборе данных.Пример:

'2012-02-18 22:00:00.000000'
'2012-02-19 23:00:00.000000' 
'2012-02-21 01:00:00.000000'

Теперь среднее значение должно быть (22 + 23 + 1) / 3 = 15,33 или 15:20 (15:20).Но это могло бы искажать данные, поскольку все эти события происходят ночью, с 22:00 до 01:00 (с 22:00 до 01:00).Действительно, лучшим подходом было бы усреднить их как (22 + 23 + 25 ) / 3 = 23,33 или 23:20 (11:20 вечера).average of times illustration

Q2) Что-нибудь, что я должен сделать с моим запросом SELECT, чтобы принять это во внимание, или это то, что я должен кодировать в Python?

Ответы [ 4 ]

2 голосов
/ 02 марта 2012

что вы действительно хотите вычислить?

  • datetime (или время в течение 1 дня) обычно представлены как действительные числа
  • координаты времени на 24-часовых часах являются комплексными числами , однако
  • среднее из представлений действительных чисел времени даст вам сомнительные результаты ...

Я не знаю, что вы хотите сделать с крайними случаями, такими как [1:00, 13:00], но давайте рассмотрим следующий пример : [01:30, 06:30, 13:20, 15:30, 16:15, 16:45, 17:10] enter image description here

Я предлагаю реализовать этот алгоритм - в Python :

  1. преобразовать время в комплексные числа - например, вычислить их координаты по окружности радиуса = 1
  2. вычислить среднее значение, используя сложение векторов
  3. преобразование угла вектора результата в минуты + вычисление релевантности этого результата (например, релевантность среднего значения [1:00, 13:00] должна быть 0 независимо от того, какой угол вычислен из-за ошибок округления)
import math
def complex_average(minutes):
    # first convert the times from minutes (0:00 - 23:59) to radians
    # so we get list for quasi polar coordinates (1, radians)
    # (no point in rotating/flipping to get real polar coordinates)
    # 180° = 1/2 day = 24*60/2 minutes
    radians = [t*math.pi/(24*60/2) for t in minutes]
    xs = []
    ys = []
    for r in radians:
        # convert polar coordinates (1, r) to cartesian (x, y)
        # the vectors start at (0, 0) and end in (x, y)
        x, y = (math.cos(r), math.sin(r))
        xs.append(x)
        ys.append(y)

    # result vector = vector addition
    sum_x, sum_y = (sum(ys), sum(xs))

    # convert result vector coordinates to radians, then to minutes
    # note the cumulative ROUNDING ERRORS, however
    result_radians = math.atan2(sum_x, sum_y)
    result_minutes = int(result_radians / math.pi * (24*60/2))
    if result_minutes < 0:
        result_minutes += 24*60

    # relevance = magnitude of the result vector / number of data points
    # (<0.0001 means that all vectors cancel each other, e.g. [1:00, 13:00]
    #  => result_minutes would be random due to rounding error)
    # FYI: standart_deviation = 6*60 - 6*60*relevance
    relevance = round(math.sqrt(sum_x**2 + sum_y**2) / len(minutes), 4)

    return result_minutes, relevance

И проверить это так:

# let's say the select returned a bunch of integers in minutes representing times
selected_times = [90, 390, 800, 930, 975, 1005, 1030]
# or create other test data:
#selected_times = [hour*60 for hour in [23,22,1]]

complex_avg_minutes, relevance = complex_average(selected_times)
print("complex_avg_minutes = {:02}:{:02}".format(complex_avg_minutes//60,
                                                 complex_avg_minutes%60),
      "(relevance = {}%)".format(int(round(relevance*100))))

simple_avg = int(sum(selected_times) / len(selected_times))
print("simple_avg = {:02}:{:02}".format(simple_avg//60,
                                        simple_avg%60))

hh_mm = ["{:02}:{:02}".format(t//60, t%60) for t in selected_times]
print("\ntimes = {}".format(hh_mm))

Вывод для моего примера:

complex_avg_minutes = 15:45 (relevance = 44%)
simple_avg = 12:25
0 голосов
/ 12 июля 2012

На сайте Rosetta Code есть задание и код на эту тему, а при исследовании я наткнулся на эту википедию ссылка .Посетите также страницы обсуждения / обсуждения для обсуждения применимости и т. Д.

0 голосов
/ 02 марта 2012

Если я правильно понимаю, вы хотите получить среднее расстояние от полуночи?

Как насчет этого?

SELECT SUM(mins) / COUNT(*) from
( SELECT
    CASE 
    WHEN strftime('%H', t) * 1 BETWEEN 0 AND 11 
    THEN (strftime('%H', t)) * 60 + strftime('%M', t)
    ELSE strftime('%H', t) * 60 + strftime('%M', t) - 24 * 60
    END mins
  FROM timestamps
);

Итак, мы рассчитаем смещение минут от полуночи: послев полдень мы получаем отрицательное значение, до полудня - положительное.Первая строка их усредняет и дает нам результат в считанные минуты.Преобразование этого времени обратно в hh:mm оставляется как «упражнение для студента»; -)

0 голосов
/ 02 марта 2012

Я не уверен, что вы можете усреднять даты.

Что я хотел бы сделать, это получить среднее значение разницы в часах между значениями строк и фиксированной датой, а затем добавить это среднее к фиксированной дате.Использование минут может привести к переполнению int и потребует некоторого преобразования типов

вроде ...

select dateadd(hh,avg(datediff(hh,getdate(),myrow)),getdate()) 
from mytable;
...