第三章:数字、日付と時間

8929 ワード

Pythonで整数と浮動小数点数を数値計算するのは簡単ですが、点数、配列、日付、時間を計算する必要がある場合は、より多くの作業を完了する必要があります.
1.数値の整列
問題:私たちは浮動小数点数を固定的な小数位にしたいと思っています.
ソリューション:簡単な整列操作には、組み込まれたround(value,ndigits)関数を使用すればよい.
>>> round(1.234565,2)
1.23

2.正確な小数計算を実行する
問題:小数点数を正確に計算する必要があり、浮動小数点数の生まれつきの誤差に影響を与えたくない.
ソリューション:より高い精度が期待される場合(パフォーマンスを犠牲にしたい場合)、decimalモジュールを使用します.
>>> from decimal import Decimal
>>> a = Decimal('4.2')
>>> b = Decimal('2.1')
>>> a+b
Decimal('6.3')
>>> print(a+b)
6.3

decimalモジュールの主な機能では、数値の次元数と四捨五入を含む計算プロセスのさまざまな態様を制御できます.
3.数値をフォーマット出力する
問題:数値をフォーマットして出力する必要があります.制御ビット数、位置合わせ、千分位区切り記号、その他の詳細が含まれています.
ソリューション:個別の数値をフォーマット出力するには、組み込まれたformat()関数を使用します.
>>> x = 123.45678
>>> format(x,'0.2f')
'123.46'
>>> format(x,'>10.1f')
'     123.5'
>>> format(x,'*>10.1f')
'*****123.5'

多くのpythonコードでは、%で処理をフォーマットすることがわかります.
>>> '%0.2f' % x
'123.46'

4.2進数、8進数、16進数と付き合う
質問:バイナリ、8進数、16進数で表される数値を変換または出力する必要があります.
解決策:整数をバイナリ、8進数、16進数のテキスト文字列形式に変換するには、内蔵bin()、oct()、hex()関数をそれぞれ使用すればよい.
5.バイト列からの大整数のパッケージングとデパッケージング
質問:バイト列があり、整数値に解く必要があります.また、大きな整数を1バイト列に再変換する必要があります.
ソリューション:バイトを整数として解釈するには、int.from_を使用します.bytes()メソッド;大きな整数をバイト列に再変換するには、int.to_を使用します.bytes()メソッド;
6.複素演算
7.処理無限大とNaN
問題:浮動小数点数と無限大、負無限大またはNaN(not a number)を判断する必要がある.
解決策:Pythonはこれらの特殊な浮動小数点数値を表す特殊な構文を持っていませんが、float()で作成できます.本がこれらの値を表示していないかどうかをチェックします.mathを使用できます.isinf()とmath.isnan()関数
8.点数の計算
>>> from fractions import Fraction
>>> a = Fraction(5,4)
>>> b = Fraction(7,16)
>>> print(a+b)
27/16
>>> print(a*b)
35/64
>>> c = a * b
>>> c.numerator
35
>>> c.denominator
64

9.大規模配列の計算処理
質問:配列やグリッドなどの大規模なデータセットを計算する必要があります.
ソリューション:配列に関連する計算密集型タスクについては、Numpyライブラリを使用します.Numpyの主な特性はPythonに配列オブジェクトを提供することである.
>>> x = [1,2,3,4]
>>> y = [5,6,7,8]
>>> x*2
[1, 2, 3, 4, 1, 2, 3, 4]
>>> x + y
[1, 2, 3, 4, 5, 6, 7, 8]
>>> x + 10
Traceback (most recent call last):
  File "", line 1, in 
TypeError: can only concatenate list (not "int") to list
>>> #Numpy arrays
>>> import numpy as np
>>> ax = np.array([1,2,3,4])
>>> ay = np.array([5,6,7,8])
>>> ax * 2
array([2, 4, 6, 8])
>>> ax + 10
array([11, 12, 13, 14])
>>> ax + ay
array([ 6,  8, 10, 12])
>>> ax * ay
array([ 5, 12, 21, 32])


Numpyは、mathモジュールで対応する関数として置き換えることができる配列を操作する「汎用関数」の集合を提供します.
>>> np.sqrt(ax)
array([ 1.        ,  1.41421356,  1.73205081,  2.        ])
>>> np.cos(ax)
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])>>> np.sqrt(ax)
array([ 1.        ,  1.41421356,  1.73205081,  2.        ])
>>> np.cos(ax)
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])

Numpyの汎用関数を使用すると、配列を反復してmathモジュールの関数を使用するよりも効率が100倍も速くなります.したがって、可能な限り使用する必要があります.
>>> a = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
>>> a
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
>>> a[1]
array([5, 6, 7, 8])
>>> a[:,1]
array([ 2,  6, 10])
>>> a[1:3,1:3]
array([[ 6,  7],
       [10, 11]])
>>> a
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
>>> a + [100,101,102,103]
array([[101, 103, 105, 107],
       [105, 107, 109, 111],
       [109, 111, 113, 115]])
>>> np.where(a<10,a,10)
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 10, 10]])

10.行列と線形代数の計算
問題:行列乗算、行列式の求め、線形方程式の解など、行列と線形代数の操作を実行する必要があります.
ソリューション:この状況を処理するために、Numpyライブラリにmatrixオブジェクトがあります.
Numpyまたはmatrixの詳細については、Numpy(https://www.numpy.org)
11.ランダム選択
質問:シーケンスから要素をランダムに選択したり、乱数を生成したりしたいです.
解決策:randomモジュールには、randomなどのランダム数とランダム選択を必要とするシーンに使用できる様々な関数があります.choice():
>>> import random
>>> values = [1,2,3,4,5,6]
>>> random.choice(values)
2
>>> random.choice(values)
5
  • N個の元素を取り出すには、選択する元素を除去してさらに考察する、randomを用いることができる.sample():
  • >>> random.sample(values,2)
    [6, 2]
    >>> random.sample(values,2)
    [6, 5]
    >>> random.sample(values,3)
    [1, 3, 2]
    
  • シーケンスの中で要素の順序を乱すだけならrandomを用いることができる.shuffle():
  • >>> random.shuffle(values)
    >>> values
    [3, 6, 4, 2, 1, 5]
    >>> random.shuffle(values)
    >>> values
    [4, 3, 5, 6, 2, 1]
    
  • ランダム整数を生成するにはrandom.randint():
  • >>> random.randint(0,10)
    5
    >>> random.randint(0,10)
    8
    
  • 0-1の間に均等に分布する浮動小数点の数値を生成するにはrandomを用いることができる.random():
  • >>> random.random()
    0.9835000918969841
    >>> random.random()
    0.549302349076499
    
  • randomモジュール彩玉マット回転アルゴリズムは乱数を計算するが、これは確定的なアルゴリズムであるがrandom.seed()関数を使用して、初期シード値を変更します.
  • random.seed()                       #     os.urandom()
    random.seed(12345)                  #        
    random.seed(b'bytedata')
    

    12.時間換算
    質問:私たちのコードは簡単な時間変換作業を行う必要があります.例えば、日を秒に変換したり、時間を分に変換したりします.
    ソリューション:datetimeモジュールを使用して、異なる時間単位間の換算を完了できます.
    >>> from datetime import timedelta
    >>> a = timedelta(days=2,hours=6)
    >>> b = timedelta(hours = 4.5)
    >>> c = a + b
    >>> c.days
    2
    >>> c.seconds
    37800
    >>> c.seconds / 3600
    10.5
    >>> c.total_seconds() / 3600
    58.5
    
  • datetimeインスタンスを作成し、標準的な数学演算を使用して操作できる特定の日付と時間を表す必要があります:
  • >>> from datetime import datetime
    >>> a = datetime(2017,9,23)
    >>> print(a + timedelta(days=10))
    2017-10-03 00:00:00
    >>> b = datetime(2017,12,21)
    >>> d = b - a
    >>> d.days
    89
    >>> now = datetime.today()
    >>> print(now)
    2018-03-07 10:03:39.843345
    >>> print(now + timedelta(minutes = 10))
    2018-03-07 10:13:39.843345
    
  • ほとんどの基本的な日付と時間操作の問題について、datetimeモジュールは基本的に要求を満たしています.タイムゾーンの処理、時間範囲の曖昧化、祝日の日付の計算など、より複雑な日付問題を処理する必要がある場合は、dateutilモジュールを試してみてください.
  • >>> from dateutil.relativedelta import relativedelta
    >>> print(a)
    2017-09-23 00:00:00
    >>> a + relativedelta(months = + 1)
    datetime.datetime(2017, 10, 23, 0, 0)
    >>> a + relativedelta(months = + 4)
    datetime.datetime(2018, 1, 23, 0, 0)
    

    13.先週の5日を計算
    14.当月の日付範囲を探し出す
    質問:当月の各日付をループ反復するコードがあります.日付の範囲を計算するには、効率的な方法が必要です.
    解決策:日付をループ反復するには、すべての日付を含むリストを事前に構築する必要はありません.範囲の開始日と終了日を計算し、反復時にdatetimeを使用します.timedeltaオブジェクトは日付を増やせばいいです.
    >>> from datetime import datetime,date,timedelta
    >>> import calendar
    >>> def get_month_range(start_date = None):
    ...     if start_date is None:
    ...             start_date = date.today().replace(day=1)
    ...     _,days_in_month = calendar.monthrange(start_date.year,start_date.month)
    ...     end_date = start_date + timedelta(days = days_in_month)
    ...     return (start_date,end_date)
    ...
    >>> a_day = timedelta(days = 1)
    >>> first_day,last_day = get_month_range()
    >>> while first_day < last_day:
    ...     print(first_day)
    ...     first_day += a_day
    ...
    2018-03-01
    2018-03-02
    2018-03-03
    2018-03-04
    2018-03-05
    2018-03-06
    ...
    2018-03-30
    2018-03-31
    

    15.文字列を日付に変換
    問題:アプリケーションは文字列形式の一時データを受信しましたが、これらの文字列をdatetimeオブジェクトに変換して、文字列以外の操作を実行したいと考えています.
    解決策:Pythonの標準モジュールdatetimeはこのような問題を処理するための簡単な方案である.
    >>> from datetime import datetime
    >>> text = '2017-12-21'
    >>> y = datetime.strptime(text,'%Y-%m-%d')
    >>> y
    datetime.datetime(2017, 12, 21, 0, 0)
    >>> z = datetime.now()
    >>> z
    datetime.datetime(2018, 3, 7, 10, 21, 58, 139168)
    >>> diff = z - y
    >>> diff
    datetime.timedelta(76, 37318, 139168)
    

    datetime.strptime()メソッドでは、%Yが4を数字で表す年を表すなど、多くのフォーマットコードがサポートされています.strptime()の性能は通常、私たちが想像していたよりもずっと悪い.これは、この関数が純粋なPythonコードで実現され、様々なシステム領域設定を処理する必要があるからである.
    datetime.timedelta(76, 37318, 139168)
    >>> from datetime import datetime
    >>> def parse_ymd(s):
    ...     year_s,month_s,day_s = s.split('-')
    ...     return datetime(int(year_s),int(month_s),int(day_s))
    ...
    >>> parse_ymd(text)
    datetime.datetime(2017, 12, 21, 0, 0)
    

    テストにより、上の関数はdatetimeより大きい.strptime()は7倍以上速くなった.日付に関するデータを大量に処理する必要がある場合は、この問題を考慮する必要があります.
    16.失われた日付に関する問題の処理