2015-03-31 60 views
12

以数字形式给出一个月份(例如,2月份为2),您如何找到其各个季度的第一个月份(例如,1月份为1)?Python中给定月份的第一个月

我通过datetime模块文档和他们的日期时间函数的熊猫文档阅读,这应该是相关的,但我找不到解决此问题的函数。

从本质上讲,我想了解的是我怎么能产生像一个低于一个函数,给定月份X,输出与X的季度第一个月的数量。

>> first_month_quarter(5) 
4 
+7

不公平的,这将是在未来类似的问题有用的人。我希望在尝试解决这个问题时我可以自己找到答案。对于自我回答,SO政策很好:http://stackoverflow.com/help/self-answer。 – 2015-03-31 18:34:38

+1

你认为有多少人会有“类似的问题”*,但无法自己解决这个问题?此外,这并不公平 - 这不是针对任何**的代码编写服务。 SO政策没问题,对主题问题**有很好的答案**,这并不意味着您可以发布任何您想要的内容。 – jonrsharpe 2015-03-31 18:36:20

+0

@jonrsharpe:OP也是第一个回答者。 – unutbu 2015-03-31 18:36:35

回答

19

这是一个简单的绘图功能,需要转换:

1 2 3 4 5 6 7 8 9 10 11 12 
      | 
      V 
1 1 1 4 4 4 7 7 7 10 10 10 

这可以在许多完成用积分计算的方法S,其中两个是:

def firstMonthInQuarter(month): 
    return (month - 1) // 3 * 3 + 1 

和:

def firstMonthInQuarter(month): 
    return month - (month - 1) % 3 

首先涉及到一个月的整数除法转换为一个从零开始的一个月拿到从零开始季度,乘法把这一回到基于零的月份(但是本月的开始),然后再次添加一个以使范围为1..12

month -1 //3 *3 +1 
----- -- --- -- -- 
    1 0 0 0 1 
    2 1 0 0 1 
    3 2 0 0 1 
    4 3 1 3 4 
    5 4 1 3 4 
    6 5 1 3 4 
    7 6 2 6 7 
    8 7 2 6 7 
    9 8 2 6 7 
    10 9 3 9 10 
    11 10 3 9 10 
    12 11 3 9 10 

第二只减去四分之一内的位置(0,1,2)从月本身,以获得开始的月份。

month(a) -1 %3(b) a-b 
-------- -- ----- --- 
     1 0  0 1 
     2 1  1 1 
     3 2  2 1 
     4 3  0 4 
     5 4  1 4 
     6 5  2 4 
     7 6  0 7 
     8 7  1 7 
     9 8  2 7 
     10 9  0 10 
     11 10  1 10 
     12 11  2 10 
10

这是TigerhawkT3建议的答案。也许迄今为止最尖锐的建议,显然也是最快的。

import math 

def first_month_quarter(month): 
    return int(math.ceil(month/3.)) * 3 - 2 

例如:

>> first_month_quarter(5) 
4 
+2

标准的'math'模块也有一个'ceil'功能,在功能上等同于此。 – TigerhawkT3 2015-03-31 18:42:16

+0

好点!我从来没有真正知道如何选择'numpy'和'math'的'ceil'函数。不知道他们的效率和产量如何/何时不同。 – 2015-03-31 18:44:25

+1

您也可以使用'((月 - 1)// 3%4)* 3 + 1',它在1和12之间的月份(含)之间一致,并且总是返回月1,4,7或1月中的一个10'为'months'小于1或大于12. – unutbu 2015-03-31 18:49:11

13
def first_month(month): 
    return (month-1)//3*3+1 

for i in range(1,13): 
    print i, first_month(i) 
+0

这就是我的答案,因为在问及时我没有睡着:-)转换为基于零的月份数并只使用整数数学。 – paxdiablo 2015-04-01 01:32:36

20

这不是那么漂亮,但如果速度是很重要的一个简单的列表查找屠杀math

def quarter(month, quarters=[None, 1, 1, 1, 4, 4, 4, 
          7, 7, 7, 10, 10, 10]): 
    """Return the first month of the quarter for a given month.""" 
    return quarters[month] 

一个timeit比较表明,这是大概是TigerhawkT3的数学方法的两倍。


测试脚本:

import math 

def quarter(month, quarters=[None, 1, 1, 1, 4, 4, 4, 
          7, 7, 7, 10, 10, 10]): 
    """Return the first month of the quarter for a given month.""" 
    return quarters[month] 

def firstMonthInQuarter1(month): 
    return (month - 1) // 3 * 3 + 1 

def firstMonthInQuarter2(month): 
    return month - (month - 1) % 3 

def first_month_quarter(month): 
    return int(math.ceil(month/3.)) * 3 - 2 

if __name__ == '__main__': 
    from timeit import timeit 
    methods = ['quarter', 'firstMonthInQuarter1', 'firstMonthInQuarter2', 
       'first_month_quarter'] 
    setup = 'from __main__ import {}'.format(','.join(methods)) 
    results = {method: timeit('[{}(x) for x in range(1, 13)]'.format(method), 
           setup=setup) 
       for method in methods} 
    for method in methods: 
     print '{}:\t{}'.format(method, results[method]) 

结果:

quarter: 3.01457574242 
firstMonthInQuarter1: 4.51578357209 
firstMonthInQuarter2: 4.01768559763 
first_month_quarter: 8.08281871176 
+9

当答案稍后出现时,提出速度声明总是有风险的。对于千万次迭代,你的方法需要7.2秒,但我的答案中的两个是7.0和7.3。事实上,即使是数学的一个时钟在7.6,所以它不是那么糟糕。不是说你的解决方案不好(实际上这个地段之间几乎没有什么区别),只是说你可能想回复一些关于索赔的问题:-)无论如何,谢谢你对'timeit'的教育,我会没见过之前 – paxdiablo 2015-04-02 13:40:33

+0

@paxdiablo真的!然而,我只是重新运行了测试,包括你的方法,并且看到了类似的结果 - 使用列表的速度是“math.ceil”的两倍以上,比整数运算速度快25-50%('timeit'默认为1,000,000次迭代)。我已经用我的测试和结果更新了答案。 – jonrsharpe 2015-04-02 14:15:05

2

包装查找表转换为64位的文字:

def firstMonthOfQuarter(month): 
    return (0x000aaa7774441110L >> (month << 2)) & 15 
相关问题