簡單談談數據的歸一化問題(Python)

開發過程中經常遇到需要把數據歸一化處理的情況,簡單記錄幾種歸一化方法。

需求1:歸一化(將一組數轉換到[0~1]區間內)一組數據,數據包含正負數,歸一化後的數據列保持其原數據列的大小順序。

def normalization(data):
    """
    歸一化函數
    把所有數據歸一化到[0,1]區間內,數據列表中的最大值和最小值分別映射到1和0,所以該方法一定會出現端點值0和1。
    此映射是線性映射,實質上是數據在數軸上等比縮放。
    
    :param data: 數據列表,數據取值範圍:全體實數
    :return:
    """
    min_value = min(data)
    max_value = max(data)
    new_list = []
    for i in data:
        new_list.append((i-min_value) / (max_value-min_value))
    return new_list


if __name__ == '__main__':
    d = [-3, 4, 6, -1, -5]
    
    print(normalization(d))
    # [0.18181818181818182, 0.8181818181818182, 1.0, 0.36363636363636365, 0.0]

上述方法滿足了需求,需要注意的是,這個方法會使歸一化結果中出現端點值(即0和1)


需求2:歸一化一組數據(包含正負數),並使得歸一化後的數據和爲1,保持其原數據的大小順序。

分析:要使得歸一化結果和爲1,就需要考慮先求和,後逐個求比值。

def softmax_linear_mapping(data):
    """
    線性映射歸一化函數。歸一化到[0, 1]區間,且和爲1。歸一化後的數據列依然保持原數據列中的大小順序。
    侷限性:僅適用於非負數據
    
    :param data: 非負數據列,數據取值範圍:非負數
    :return:
    """
    sum_all = sum(data)
    new_list = []
    for i in data:
        new_list.append(i / sum_all)
    return new_list


if __name__ == '__main__':
    d = [3, 4, 6, 1, 5]
    print(softmax_linear_mapping(d))
    # [0.15789473684210525, 0.21052631578947367, 0.3157894736842105, 0.05263157894736842, 0.2631578947368421]
    
    d = [-3, 4, 6, -1, -5]
    print(softmax_linear_mapping(d))
    # [-3.0, 4.0, 6.0, -1.0, -5.0]

但不幸的是,這個方法有先天缺陷:不能處理負數列。

爲了解決這個問題,嘗試引入一個非線性函數,將數據區間(-∞, +∞)映射到(0, +∞)上,這樣就可以愉快的玩耍了。

優化 [社會我白哥,人狠話不多]

import math
def softmax(data):
    """
    非線性映射歸一化函數。歸一化到[0, 1]區間,且和爲1。歸一化後的數據列依然保持原數據列中的大小順序。
    非線性函數使用以e爲底的指數函數:math.exp()。
    使用它可以把輸入數據的範圍區間(-∞, +∞)映射到(0, +∞),這樣就可以使得該函數有能力處理負數。
    
    :param data: 數據列,數據的取值範圍是全體實數
    :return:
    """
    exp_list = [math.exp(i) for i in data]
    sum_exp = sum(exp_list)
    new_list = []
    for i in exp_list:
        new_list.append(i / sum_exp)
    return new_list


if __name__ == '__main__':

    d = [3, 4, 6, 1, 5]
    print(softmax(d))
    # [0.031920112758713086, 0.0867678624743735, 0.6411326034074455, 0.0043199175011450494, 0.235859503858323]
    d = [-3, 4, 6, -1, -5]
    print(softmax(d))
    # [0.00010859836836988283, 0.11909257170564182, 0.8799816932989085, 0.0008024394361374001, 1.4697190942372094e-05]

~ 完美 ~

Mr.bai

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章