【问题标题】:Choose a random month from the past 2 years in Python在 Python 中从过去 2 年中选择一个随机月份
【发布时间】:2018-06-17 03:03:34
【问题描述】:

我想在今年和 2016 年之间随机选择一个月份。 这是我目前非常天真的解决方案

from random import choice
def get_month():
    return choice({'2018-06','2018-05','2018-04','2018-03'})

很明显,这个集合在未来会变得太大,那么有什么更好的方法来实现这一点?

【问题讨论】:

  • 在什么意义上你需要随机性?二月比三月短。 2 月应该有~28.25/365.25 被选中的概率吗?还是每个月都有1/12 被选中的机会?当前月份呢?这个月应该有16/365.25 被选中的概率吗?
  • 每个月应该有 1/12 的机会被选中。

标签: python random


【解决方案1】:

也许你可以有两个月份和年份的列表,这些将被修复。然后,您可以在每个之间随机选择并指定返回日期。这样我认为就不需要生成所有不同的日期,也不需要存储在大列表中:

from random import choice
def get_month():
    months = list(range(1, 13)) # 12 months list
    year = list(range(2016, 2019)) # years list here
    val = '{}-{:02d}'.format(choice(year), choice(months))
    return val

get_month()

结果:

'2017-05'

更新

以防万一如果选择的年份是当前年份,则不超过当前月份,您可能需要if 条件来生成月份列表,如下所示:

from random import choice
from datetime import datetime

def get_month():

    today = datetime.today() # get current date
    year = list(range(2016, today.year+1)) # list till current date year

    # randomly select year and create list of month based on year
    random_year = choice(year)

    # if current year then do not exceed than current month
    if random_year == today.year:
        months = list(range(1, today.month+1))
    else:
        # if year is not current year then it is less so can create 12 months list
        months = list(range(1, 13)) 

    val = '{}-{:02d}'.format(random_year, choice(months))

    return val

【讨论】:

  • @MadPhysicist 我认为它不会超过当前月份和当前年份。有什么问题吗?
  • 有些月份比其他月份大。有些年份的月份比其他年份的月份大。
  • @MateenUlhaq 我不太确定我是否理解,我可能在随机选择上遗漏了一点。但这是否意味着几个月的天数?我认为如果年份过去或到当前月份,它将有 12 个月。
  • 这取决于 OP 在这里真正寻找的分布。 (出于什么目的/应用?)我的观点是,为了日期的适当一致性,2 月应该(平均)有~28.25/365.25 被选中的机会。这个百分比取决于年份(可能还有其他因素)。
  • 当年过去的月份应该有更高的被选中概率。
【解决方案2】:

您可以使用库pandas 和使用date_range

choice(pd.date_range(start="2016-01-01", end="2018-01-01", freq='M'))

如果您想要它直到今天,您可以将 startend 参数替换为任何合适的参数,例如

from dateutil.relativedelta import relativedelta
today = datetime.today()
two_years_ago = today - relativedelta(years=2)
choice(pd.date_range(start=two_years_ago, end=today, freq='M'))

【讨论】:

  • “today - relativedelta(years=2)”会包括 2016 年 1 月还是过去 24 个月?您认为硬编码开始日期并避免导入 relativedelta 会更好吗?
  • 这取决于你的意图。如果你真的想要always 从 2016 年 1 月到今天,我认为你可以对其进行硬编码。如果您总是想要一个准确的 2 年时间框架,那么建议使用相对增量 :)
【解决方案3】:

我希望我的代码能给你一些启发。

 import random
 import datetime

 def RandomMonth(st_year, st_month, ed_year, ed_month):
     """st_year, st_month and ed_year/month is int. """
     start_date = datetime.datetime(st_year, st_month, 1)
     end_date = datetime.datetime(ed_year, ed_month, 31)
     d_days = (end_date - start_date).days
     r_days = random.randint(0, ttl_days)
     r_date = start_date + datetime.timedelta(days = r_days)
     return r_date.strftime("%B/%Y")

【讨论】:

    【解决方案4】:

    您已正确识别问题。虽然离散项目集很快就会变得笨拙(实际上不会),但选择 random integer over an arbitrary range 很容易。

    您应该能够轻松计算您感兴趣的日期之间的月数。这意味着您有一个从月份到整数的简单的一对一映射。现在你可以做

    m = random.randrange(N)
    

    其中N 是您的总月数(当月数 + 12 * 整年数)。使用 Python 的 datetime API 很容易映射回月份:

    origin = datetime.date(2016, 1, 1)
    today = datetime.today()
    n = (today.year - origin.year) * 12 + today.month - origin.month
    
    m = random.randrange(n)
    x = origin.replace(year=origin.year + m // 12, month=origin.month + m % 12)
    

    基于this answer 的月增量(n)和基于this answer 的月增量(x)。如果您将原点从 1 月移开,这两种计算都会变得稍微复杂一些。

    【讨论】:

      【解决方案5】:

      随便选一个 1-24 然后从当前日期开始应用一些日期算术来登陆您的月份。

      from datetime import datetime, date
      from dateutil.relativedelta import relativedelta
      from random import randint
      
      refdate = date.today() #datetime.now() works too!
      for i in range(0,10):
          #this will take off at least 1 month and 24 will return 2016-06 from 2018-06
          months = randint(1,24)  
          back = refdate - relativedelta(months=months)
          print ("start:%s - %02d months => %s" % (refdate, months, back))
      

      输出:

      start:2018-06-17 - 24 months => 2016-06-17
      start:2018-06-17 - 22 months => 2016-08-17
      start:2018-06-17 - 21 months => 2016-09-17
      start:2018-06-17 - 08 months => 2017-10-17
      start:2018-06-17 - 16 months => 2017-02-17
      start:2018-06-17 - 06 months => 2017-12-17
      start:2018-06-17 - 07 months => 2017-11-17
      start:2018-06-17 - 14 months => 2017-04-17
      start:2018-06-17 - 07 months => 2017-11-17
      start:2018-06-17 - 07 months => 2017-11-17
      

      【讨论】:

        【解决方案6】:

        你可以把它们分开做,比如随机年份和随机月份,然后把它们放在一起

        def get_month():
            year = random.choice([2016, 2017, 2018])
            month = random.choice(range(1,13))
            new_date = str(year) + "-" + str(month)
            return new_date
        

        【讨论】:

        • 这不统一,因为当年没有所有月份。
        【解决方案7】:

        尝试使用calendar

        from random import choice
        import calendar
        def get_month():
            l = []
            y = 0
            for i in range(2016,2019):
                l.append(str(i)+'-'+str(calendar.monthrange(i,12)[0]))
            return choice(l)
        print(get_month())
        

        【讨论】:

          【解决方案8】:

          我想我的解决方案比使用 pandas 的解决方案更轻松

          current_month = datetime.today().month
          current_year = datetime.today().year 
          start_year = 2016
          
          #total months between now and the start year
          total_months = current_month + (current_year - start_year)*12 
          
          months = []
          month_count = 1
          year_count = start_year
          
          #iterate through the list, when it reaches 13, increment year_count and reset the month_count to 1
          for month in range(total_months):
              if month_count<13:
                  months.append(str(year_count) + "-" + str("{0:0=2d}".format(month_count)))
                  month_count+=1
              if month_count == 13:
                  year_count+=1
                  month_count=1
          

          结果

          ['2016-01', '2016-02', '2016-03', '2016-04', '2016-05', '2016-06', '2016-07', '2016-08', '2016-09', '2016-10', '2016-11', '2016-12', '2017-01', '2017-02', '2017-03', '2017-04', '2017-05', '2017-06', '2017-07', '2017-08', '2017-09','2017-10', '2017-11', '2017-12', '2018-01', '2018-02', '2018-03', '2018-04', '2018-05', '2018-06']
          

          由于某种原因,当我将“if month_count == 13”替换为“else”时,它只会上升到 2018-04

          如果您对此解决方案提供一些反馈,我将不胜感激。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-09-28
            • 2021-02-03
            • 1970-01-01
            • 1970-01-01
            • 2019-09-18
            • 2015-10-19
            相关资源
            最近更新 更多