【问题标题】:Python calculate request rate per hour for each IPPython计算每个IP每小时的请求率
【发布时间】:2019-04-09 08:18:20
【问题描述】:

我有一个格式如下的字典 {str: [datetime_object]}

示例:

test_data={'127.0.0.1':[datetime.datetime(2016, 5, 31, 2, 3, 48), datetime.datetime(2016, 5, 31, 3, 0, 53)],
    '127.0.0.2':  [datetime.datetime(2016, 5, 30, 0, 15, 10), datetime.datetime(2016, 5, 31, 2, 18, 29), datetime.datetime(2016, 5, 31, 2, 18, 41), datetime.datetime(2016, 5, 31, 2, 18, 49), datetime.datetime(2016, 5, 31, 2, 21, 32), datetime.datetime(2016, 5, 31, 2, 21, 40), datetime.datetime(2016, 5, 31, 2, 21, 46), datetime.datetime(2016, 5, 31, 2, 22), datetime.datetime(2016, 5, 31, 23, 0, 0)],
    '127.0.0.3':  [datetime.datetime(2016, 5, 31, 2, 19, 34), datetime.datetime(2016, 5, 31, 2, 19, 39)],
    '127.0.0.4':  [datetime.datetime(2016, 5, 31, 2, 20, 36), datetime.datetime(2016, 5, 31, 2, 20, 41)],
    '127.0.0.5':  [datetime.datetime(2016, 5, 31, 2, 21, 5)],
    '127.0.0.6':  [datetime.datetime(2016, 5, 31, 2, 21, 6)],
    '127.0.0.7':  [datetime.datetime(2016, 5, 31, 2, 21, 5)],
    '127.0.0.8':  [datetime.datetime(2016, 5, 31, 2, 21, 34), datetime.datetime(2016, 5, 31, 2, 21, 38)],
    '127.0.0.9': [datetime.datetime(2016, 5, 31, 2, 22, 3), datetime.datetime(2016, 5, 31, 2, 23, 5)],
    '127.0.0.10':  [datetime.datetime(2016, 5, 31, 2, 10, 22), datetime.datetime(2016, 5, 31, 2, 12, 27)],
    '127.0.0.11':  [datetime.datetime(2016, 5, 31, 3, 11, 46), datetime.datetime(2016, 5, 31, 3, 13, 54)],
    '127.0.0.12':  [datetime.datetime(2016, 5, 31, 3, 13, 9), datetime.datetime(2016, 5, 31, 3, 13, 17)]}

这些条目是从每个 IP 收到的请求日期时间

我需要计算每个 IP 每小时的平均请求数

我当前的尝试在此代码处结束

def count_accesses():
    for key, value in ip_request_datetime_dict.items():
        for recived in value:
            yield recived.hour

for x in count_accesses():
    print(x)

以上代码基于此解决方案 How to count accesses per hour from log file entries?

正确的解决方案输出可能是包含汇率的字典。示例:

  • 这个 127.0.0.1 的平均请求率为每小时 2 个请求,因为您可以看到 02:03:48 -> 03:00:53 仍有 3 分钟来计算整小时

  • 这个 127.0.0.2 的平均请求率为每小时 3 个请求

    ip_hit_rate = {'127.0.0.1': 2, '127.0.0.2': 3, '127.0.0.3': 2, '127.0.0.4': 2, '127.0.0.5': 1, “127.0.0.6”:1}

非常感谢任何帮助

【问题讨论】:

  • 列表是否保证排序?
  • 为什么127.0.0.1 每小时有 2 个请求? test_data 中的 ip 条目是在不同日期创建的?
  • 我不明白你平均每小时....参考小时是多少?
  • @Chris 感谢您的指出,我已更正了问题
  • @Frenchy 一个IP每小时收到多少请求,我们需要计算每个IP每小时的平均请求数

标签: python algorithm


【解决方案1】:

使用itertools.groupby:

import itertools

res = {}
for k,v in test_data.items():  
    counts = [len(list(g)) for _, g in itertools.groupby(sorted(v), lambda x:(x.year, x.month, x.day, x.hour))]
    res[k] = round(sum(counts)/len(counts))

输出:

{'127.0.0.1': 1,
 '127.0.0.10': 2,
 '127.0.0.11': 2,
 '127.0.0.12': 2,
 '127.0.0.2': 3,
 '127.0.0.3': 2,
 '127.0.0.4': 2,
 '127.0.0.5': 1,
 '127.0.0.6': 1,
 '127.0.0.7': 1,
 '127.0.0.8': 2,
 '127.0.0.9': 2}

【讨论】:

  • 谢谢@Chris,这看起来更正确。如果它可以对结果进行四舍五入,那就太好了,因为该结果将被放入报告中。例如每小时 1.5 个请求可以四舍五入为 2
  • @Salama 当然。您可以使用round。请参考编辑:)
  • 干得好,请您再次修改解决方案,使其更准确,例如'127.0.0.1': [datetime.datetime(2016, 5, 31, 2, 3, 48), datetime.datetime(2016, 5, 31, 3, 0, 53)],每小时的平均请求数是 2,因为你可以看到 02:03:48 -> 03:00 还有 3 分钟来计算整小时: 53,但目前的解决方案给出了 1
  • @Salama 您提供的示例与示例不同('127.0.0.1':[datetime.datetime(2016, 5, 28, 2, 3, 48), datetime.datetime(2016, 5, 31, 2, 3, 53)]。您可以更新您的帖子并让我知道您想使用哪一个 :)
  • 我已经更新了问题,计算 2 小时之间的距离并检查它是否 > 59 分钟更准确,然后我们认为它是一个新的小时开始
【解决方案2】:

这是我计算每小时请求的方式:

import datetime

test_data={'127.0.0.1':[datetime.datetime(2016, 5, 28, 2, 3, 48), datetime.datetime(2016, 5, 31, 2, 3, 53)],
    '127.0.0.2':  [datetime.datetime(2016, 5, 30, 0, 15, 10), datetime.datetime(2016, 5, 31, 2, 18, 29), datetime.datetime(2016, 5, 31, 2, 18, 41), datetime.datetime(2016, 5, 31, 2, 18, 49), datetime.datetime(2016, 5, 31, 2, 21, 32), datetime.datetime(2016, 5, 31, 2, 21, 40), datetime.datetime(2016, 5, 31, 2, 21, 46), datetime.datetime(2016, 5, 31, 2, 22), datetime.datetime(2016, 5, 31, 23, 0, 0)],
    '127.0.0.3':  [datetime.datetime(2016, 5, 31, 2, 19, 34), datetime.datetime(2016, 5, 31, 2, 19, 39)],
    '127.0.0.4':  [datetime.datetime(2016, 5, 31, 2, 20, 36), datetime.datetime(2016, 5, 31, 2, 20, 41)],
    '127.0.0.5':  [datetime.datetime(2016, 5, 31, 2, 21, 5)],
    '127.0.0.6':  [datetime.datetime(2016, 5, 31, 2, 21, 6)],
    '127.0.0.7':  [datetime.datetime(2016, 5, 31, 2, 21, 5)],
    '127.0.0.8':  [datetime.datetime(2016, 5, 31, 2, 21, 34), datetime.datetime(2016, 5, 31, 2, 21, 38)],
    '127.0.0.9': [datetime.datetime(2016, 5, 31, 2, 22, 3), datetime.datetime(2016, 5, 31, 2, 23, 5)],
    '127.0.0.10':  [datetime.datetime(2016, 5, 31, 2, 10, 22), datetime.datetime(2016, 5, 31, 2, 12, 27)],
    '127.0.0.11':  [datetime.datetime(2016, 5, 31, 3, 11, 46), datetime.datetime(2016, 5, 31, 3, 13, 54)],
    '127.0.0.12':  [datetime.datetime(2016, 5, 31, 3, 13, 9), datetime.datetime(2016, 5, 31, 3, 13, 17)]}

def delta_to_hours(delta):
    return delta.days * 24 + delta.seconds / 3600

def calc_rate(values):
    num = len(values)
    if num <= 1:
        return 1
    diff = delta_to_hours(values[-1] - values[0])
    return num / diff

rates = {key:calc_rate(value) for key,value in test_data.items()}
print(rates)

输出是:

{
'127.0.0.1': 0.02777724195135125, 
'127.0.0.2': 0.1925248083665102, 
'127.0.0.3': 1440.0, 
'127.0.0.4': 1440.0, 
'127.0.0.5': 1, 
'127.0.0.6': 1, 
'127.0.0.7': 1, 
'127.0.0.8': 1800.0, 
'127.0.0.9': 116.12903225806451, 
'127.0.0.10': 57.599999999999994, 
'127.0.0.11': 56.25, 
'127.0.0.12': 900.0
}

【讨论】:

    【解决方案3】:

    itertools.groupby 很酷,但有时它看起来像是一种难以理解的黑暗魔法。 collections.Counter 也可以帮到你,而且更容易使用:

    import datetime
    from collections import Counter
    
    test_data={'127.0.0.1':[datetime.datetime(2016, 5, 28, 2, 3, 48), datetime.datetime(2016, 5, 31, 2, 3, 53)],
        '127.0.0.2':  [datetime.datetime(2016, 5, 30, 0, 15, 10), datetime.datetime(2016, 5, 31, 2, 18, 29), datetime.datetime(2016, 5, 31, 2, 18, 41), datetime.datetime(2016, 5, 31, 2, 18, 49), datetime.datetime(2016, 5, 31, 2, 21, 32), datetime.datetime(2016, 5, 31, 2, 21, 40), datetime.datetime(2016, 5, 31, 2, 21, 46), datetime.datetime(2016, 5, 31, 2, 22), datetime.datetime(2016, 5, 31, 23, 0, 0)],
        '127.0.0.3':  [datetime.datetime(2016, 5, 31, 2, 19, 34), datetime.datetime(2016, 5, 31, 2, 19, 39)],
        '127.0.0.4':  [datetime.datetime(2016, 5, 31, 2, 20, 36), datetime.datetime(2016, 5, 31, 2, 20, 41)],
        '127.0.0.5':  [datetime.datetime(2016, 5, 31, 2, 21, 5)],
        '127.0.0.6':  [datetime.datetime(2016, 5, 31, 2, 21, 6)],
        '127.0.0.7':  [datetime.datetime(2016, 5, 31, 2, 21, 5)],
        '127.0.0.8':  [datetime.datetime(2016, 5, 31, 2, 21, 34), datetime.datetime(2016, 5, 31, 2, 21, 38)],
        '127.0.0.9': [datetime.datetime(2016, 5, 31, 2, 22, 3), datetime.datetime(2016, 5, 31, 2, 23, 5)],
        '127.0.0.10':  [datetime.datetime(2016, 5, 31, 2, 10, 22), datetime.datetime(2016, 5, 31, 2, 12, 27)],
        '127.0.0.11':  [datetime.datetime(2016, 5, 31, 3, 11, 46), datetime.datetime(2016, 5, 31, 3, 13, 54)],
        '127.0.0.12':  [datetime.datetime(2016, 5, 31, 3, 13, 9), datetime.datetime(2016, 5, 31, 3, 13, 17)]}
    
    def extract_hour(d: datetime.datetime):
        return d.date(), d.hour
    
    result = {}
    for k, v in test_data.items():
        cnt = Counter(map(extract_hour, v))
        result[k] = sum(cnt.values()) / len(cnt)
    
    print(result)
    

    会输出

    {
        '127.0.0.1': 1.0, 
        '127.0.0.2': 3.0, 
        '127.0.0.3': 2.0, 
        '127.0.0.4': 2.0, 
        '127.0.0.5': 1.0, 
        '127.0.0.6': 1.0, 
        '127.0.0.7': 1.0, 
        '127.0.0.8': 2.0, 
        '127.0.0.9': 2.0, 
        '127.0.0.10': 2.0, 
        '127.0.0.11': 2.0, 
        '127.0.0.12': 2.0
    }
    

    【讨论】:

    • 干得好,请您再次修改解决方案,使其更准确,例如'127.0.0.1': [datetime.datetime(2016, 5, 31, 2, 3, 48), datetime.datetime(2016, 5, 31, 3, 0, 53)],每小时的平均请求数是 2,因为你可以看到 02:03:48 -> 03:00 还有 3 分钟来计算整小时: 53,但目前的解决方案给出了 1
    • 但是test_data 的日子不同了! 5 月 28 日和 5 月 31 日。
    • 感谢指出,我已经修改了问题,但仍然没有得到准确的输出
    • 我认为您可能希望更正式地定义您的目标。例如,您希望[(2016, 5, 31, 2, 5), (2016, 5, 31, 2, 25), (2016, 5, 31, 2, 30), (2016, 5, 31, 2, 35), (2016, 5, 31, 3, 10), ] 得到什么结果?
    【解决方案4】:

    这是我的解决方案,时间为一小时:

    result={}
    for k in test_data.keys():
        ref = test_data[k][0]
        counter= []
        c = 1
        for h in range(1, len(test_data[k])):
            if (test_data[k][h] - ref).total_seconds() / 3600 < 1.0:
                c = c + 1
            else:
                counter.append(c)
                c = 1
                ref = test_data[k][h]
                if h == len(test_data[k])-1:
                    counter.append(c)
    
        result[k] = float(c) if len(counter) == 0 else float(sum(counter)) / len(counter) 
    
    print(result)
    

    输出:

    {'127.0.0.1': 2.0, 
    '127.0.0.2': 3.0, 
    '127.0.0.3': 2.0, 
    '127.0.0.4': 2.0, 
    '127.0.0.5': 1.0, 
    '127.0.0.6': 1.0, 
    '127.0.0.7': 1.0, 
    '127.0.0.8': 2.0, 
    '127.0.0.9': 2.0, 
    '127.0.0.10': 2.0, 
    '127.0.0.11': 2.0, 
    '127.0.0.12': 2.0}
    

    【讨论】:

      猜你喜欢
      • 2015-01-19
      • 1970-01-01
      • 2020-02-21
      • 1970-01-01
      • 2017-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      相关资源
      最近更新 更多