美國各州急尋經費修路、電動車爽領補貼的日子將盡?

電動車爽領補貼、減免稅率的好日子快要結束?美國不少基礎建設早該翻修,各州為了尋找經費焦頭爛額,紛紛把腦筋動到電動車頭上。今(2017)年美國至少已有五州通過對電動車徵稅的法案,當中甚至包括對環保議題最為熱衷的加州。

CNBC 3日報導(見此),美國包括加州在內的不少州,已在今年通過對電動車加稅,一年徵收100-200美元不等。加州州長布朗(Jerry Brown)在今年春季通過法案時表示,安全和順暢的道路,不但能使加州成為更佳的居住地,也會提振州內經濟活動,增加數千個工作機會。

加州的決定,顯示市場對電動車的心態已有轉變。美國不少州原本都對環保汽車相當友善,提出減稅補貼等獎勵措施,鼓勵駕駛人換車。如今各州財政緊繃,道路又坑坑巴巴、亟待修整,電動車便成了眾矢之的。自2013年以來,美國24州、華盛頓哥倫比亞特區都已決定調高電動車的燃料稅(gas tax),其中加州把燃料稅調高12美分,以支應524億美元道路維修暨壅塞紓解方案的半數費用。

環保人士擔憂,這些費用可能會壓抑電動車的銷售量。不僅如此,購買電動車所享有的7,500美元聯邦減稅優惠,也會在電動車賣出20萬輛後遭到解除。根據汽車銷售暨資訊網站Edmunds.com估計,電動車對整體汽車市場的佔有率目前僅有0.6%,銷售量成長率則從2013年的227%,驟降至2016年的5%。

Barronˋs Next 5月9日報導,Edmunds當時就悲觀預測(見此),電動車聯邦減稅優惠終結將摧毀美國電動車車市。當局規定,車商的前20萬名客戶,可以獲得補助,如今特斯拉(Tesla)已售出將近10萬輛電動車,估計明年優惠就會結束。

特斯拉平價車款「Model 3」定價3.5萬美元,扣掉7,500美元補貼之後,買家等於只要付2.75萬美元,差距極為明顯。特斯拉想打入大眾車市,必須對上2萬美元的汽油車和油電混合車,少了優惠之後,兩者價差更為懸殊。

以美國喬治亞州為例,該州取消購買電動車的5,000美元稅務優惠之後,買氣急凍。有稅務優惠時,喬治亞州佔全美電動車銷售的17%;取消之後,銷售比重驟降至2%。Edmunds據此推論,補助結束後,電動車市將崩盤。Edmunds報告指出,高檔電動車較不受稅務優惠影響,但是一般買家會在意補貼。補助終結後,電動車廠必須大砍售價,才能維持買氣。

(本文內容由授權使用。圖片出處:public domain CC BY 0)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

上海新能源汽車展8月23舉行 吉利將攜帝豪PHEV亮相

進入2017年以來,上海市新能源汽車推廣應用和產業發展繼續保持高增長,1-5月新能源汽車推廣上牌數量達到10699輛。據瞭解,目前在上海市場上銷售的新能源車型累計超過100款,其中本地品牌占比為35%,其他省市品牌占比達到65%,市場累計推廣前5位的品牌依次為比亞迪、榮威、北汽、奇瑞、Tesla。

當前,上海已成為新能源汽車全球保有量最大的城市,吉利汽車自然不會放過這個巨大的市場。在最近上海市經信委公佈的4批新能源汽車備案資訊表中,吉利分別在第三批、第四批目錄中均有車型進入。據悉,吉利進入上海市新能源汽車備案資訊表中的車型為吉利帝豪EV300及吉利帝豪PHEV。

吉利帝豪EV300自推出以來,頗受市場的歡迎,今年5月還登頂了新能源汽車單車銷量排行板的第一位,而帝豪PHEV作為吉利旗下首款插電式混合動力車型,自公佈以來也是備受關注。

據瞭解,吉利帝豪PHEV外觀上與吉利帝豪EV基本相同。內飾方面,帝豪PHEV配備三輻式真皮方向盤並集成了CCS定速巡航、多媒體播放、語音控制等控制按鈕。而與帝豪EV不同的是,在中控部分帝豪PHEV增加了旋鈕式檔位,使車輛可在純電動、混合動力等模式中進行切換,增強了操作的便利性及駕駛體驗。

最亮眼的部分是帝豪PHEV採用了被稱為“聯擎”的功率分流式混合動力技術,搭載代號為JLγ-4G15H的1.5L發動機與兩台高性能電機和11.3kWh的三元鋰電池組組成的插電式混合動力系統。新車最高時速可達175km/h,NEDC工況油耗1.5L/100km,HEV模式下綜合工況油耗5.1L/100km,NEDC工況下純電續航里程61km。

作為全國插電式混合動力最大銷售城市,吉利帝豪PHEV本次順利進入上海新能源汽車目錄無疑是個極好的信號。為了與各位大咖搶佔市場份額,吉利汽車將攜帝豪EV300,帝豪PHEV亮相2017上海國際新能源汽車產業博覽會。其中帝豪PHEV是進入上海新能源汽車目錄後,首度亮相上海。

據瞭解,2017上海國際新能源汽車產業博覽會是由充電設施線上網、廣東省充電設施協會、廣東省新能源汽車產業協會、中國土木工程學會城市公共交通學會和振威展覽股份聯合舉辦,展示面積達45000平米,參展企業涵蓋了整車、核心三電(電池、電機、電控)、充電設備等產業板塊,是我國新能源汽車產業領域最專業的展覽展示和技術交流的綜合性展會平臺。

除吉利外,比亞迪、申龍客車、珠海銀隆、上汽集團、上饒客車、中植新能源、中通、江淮、眾泰、知豆、南京金龍、成功汽車、新吉奧集團、瑞馳新能源、福汽新龍馬等新能源汽車企業,以及精進電動、英威騰、東風電機、力神、沃特瑪、國軒高科、地上鐵、特來電、科陸、巴斯巴、萬馬專纜、奧美格、瑞可達等核心三電及零部件知名企業將亮相本次展會。

參觀預登記,請點擊:

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

[機器學習筆記]kNN進鄰算法

K-近鄰算法

一、算法概述

(1)採用測量不同特徵值之間的距離方法進行分類

  • 優點: 精度高、對異常值不敏感、無數據輸入假定。
  • 缺點: 計算複雜度高、空間複雜度高。

(2)KNN模型的三個要素

kNN算法模型實際上就是對特徵空間的的劃分。模型有三個基本要素:距離度量、K值的選擇和分類決策規則的決定。

  • 距離度量

    距離定義為:
    \[L_p(x_i,x_j)=\left( \sum^n_{l=1} |x_i^{(l)} – x_j^{(l)}|^p \right) ^{\frac{1}{p}}\]
    一般使用歐式距離:p = 2的個情況
    \[L_p(x_i,x_j)=\left( \sum^n_{l=1} |x_i^{(l)} – x_j^{(l)}|^2 \right) ^{\frac{1}{2}}\]

  • K值的選擇

    一般根據經驗選擇,需要多次選擇對比才可以選擇一個比較合適的K值。

    如果K值太小,會導致模型太複雜,容易產生過擬合現象,並且對噪聲點非常敏感。

    如果K值太大,模型太過簡單,忽略的大部分有用信息,也是不可取的。

  • 分類決策規則

    一般採用多數表決規則,通俗點說就是在這K個類別中,哪種類別最後就判別為哪種類型

二、實施kNN算法

2.1 偽代碼

  • 計算法已經類別數據集中的點與當前點之間的距離
  • 按照距離遞增次序排序
  • 選取與但前點距離最小的k個點
  • 確定前k個點所在類別的出現頻率
  • 返回前k個點出現頻率最高的類別作為當前點的預測分類

2.2 實際代碼

def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()     
    classCount={}          
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

三、實際案例:使用kNN算法改進約會網站的配對效果

我的朋友阿J一直使用在線約會軟件尋找約會對象,他曾經交往過三種類型的人:

  • 不喜歡的人
  • 感覺一般的人
  • 非常喜歡的人

步驟:

  • 收集數據
  • 準備數據:也就是讀取數據的過程
  • 分析數據:使用Matplotlib畫出二維散點圖
  • 訓練算法
  • 測試算法
  • 使用算法

3.1 準備數據

樣本數據共有1000個,3個特徵值,共有4列數據,最後一列表示標籤分類(0:不喜歡的人;1:感覺一般的人;2:非常喜歡的人)

特徵

  • 每年獲得的飛行常客里程數
  • 玩視頻遊戲所好的時間百分比
  • 每周消費的冰淇淋公斤數

部分數據如下:

40920   8.326976    0.953952    3
14488   7.153469    1.673904    2
26052   1.441871    0.805124    1
75136   13.147394   0.428964    1
38344   1.669788    0.134296    1
72993   10.141740   1.032955    1
35948   6.830792    1.213192    3
42666   13.276369   0.543880    3
67497   8.631577    0.749278    1
35483   12.273169   1.508053    3

讀取數據(讀取txt文件)

def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

3.2 分析數據:使用Matplotlib創建散點圖

初步分析
import matplotlib
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
ax.set_xlabel("玩視頻遊戲所耗時間百分比")
ax.set_ylabel("每周消費的冰淇淋公斤數")
plt.show()

因為有三種類型的分類,這樣看的不直觀,我們添加以下顏色

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))
ax.set_xlabel("玩視頻遊戲所耗時間百分比")
ax.set_ylabel("每周消費的冰淇淋公斤數")
plt.show()

通過都多次的嘗試后發現,玩遊戲時間和冰淇淋這個兩個特徵關係比較明顯

具體的步驟:

  • 分別將標籤為1,2,3的三種類型的數據分開
  • 使用matplotlib繪製,並使用不同的顏色加以區分
datingDataType1 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==1])
datingDataType2 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==2])
datingDataType3 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==3])
                   

fig, axs = plt.subplots(2, 2, figsize = (15,10))
axs[0,0].scatter(datingDataType1[:,0], datingDataType1[:,1], s = 20, c = 'red')
axs[0,1].scatter(datingDataType2[:,0], datingDataType2[:,1], s = 30, c = 'green')
axs[1,0].scatter(datingDataType3[:,0], datingDataType3[:,1], s = 40, c = 'blue')
type1 = axs[1,1].scatter(datingDataType1[:,0], datingDataType1[:,1], s = 20, c = 'red')
type2 = axs[1,1].scatter(datingDataType2[:,0], datingDataType2[:,1], s = 30, c = 'green')
type3 = axs[1,1].scatter(datingDataType3[:,0], datingDataType3[:,1], s = 40, c = 'blue')
axs[1,1].legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2)
axs[1,1].set_xlabel("玩視頻遊戲所耗時間百分比")
axs[1,1].set_ylabel("每周消費的冰淇淋公斤數")

plt.show()

3.3 準備數據:數據歸一化

通過上面的圖形繪製,發現三個特徵值的範圍不一樣,在使用KNN進行計算距離的時候,數值大的特徵值就會對結果產生更大的影響。

數據歸一化:就是將幾組不同範圍的數據,轉換到同一個範圍內。

公式: newValue = (oldValue – min)/(max – min)

def autoNorm(dataSet):
    minVals = dataSet.min(0) # array([[1,20,3], [4,5,60], [7,8,9]])   min(0) = [1, 5, 3]
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normData = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normData = (dataSet - tile(minVals, (m,1)))/tile(ranges,(m,1))
    return normData

3.4 測試算法

我們將原始樣本保留20%作為測試集,剩餘80%作為訓練集

def datingClassTest():
    hoRatio = 0.20  
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file
    normMat = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:,:],datingLabels[numTestVecs:],3)
        if (classifierResult != datingLabels[i]): 
            errorCount += 1.0
    print ("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print (errorCount)

運行結果

the total error rate is: 0.080000
16.0

四、源代碼

from numpy import *
import operator
from os import listdir

import matplotlib
import matplotlib.pyplot as plt
    
## KNN function
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()     
    classCount={}          
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

# read txt data
def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector


def autoNorm(dataSet):
    minVals = dataSet.min(0) # array([[1,20,3], [4,5,60], [7,8,9]])   min(0) = [1, 5, 3]
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normData = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normData = (dataSet - tile(minVals, (m,1)))/tile(ranges,(m,1))
    return normData
    
    
    
    
def drawScatter1(datingDataMat, datingLabels):
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']

    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
    ax.set_xlabel("玩視頻遊戲所耗時間百分比")
    ax.set_ylabel("每周消費的冰淇淋公斤數")
    plt.show()
    
def drawScatter2(datingDataMat, datingLabels):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
    ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))
    ax.set_xlabel("玩視頻遊戲所耗時間百分比")
    ax.set_ylabel("每周消費的冰淇淋公斤數")
    plt.show()
    
    
def drawScatter3(datingDataMat, datingLabels):
    datingDataType1 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==1])
    datingDataType2 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==2])
    datingDataType3 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==3])

    fig, axs = plt.subplots(2, 2, figsize = (15,10))
    axs[0,0].scatter(datingDataType1[:,0], datingDataType1[:,1], s = 20, c = 'red')
    axs[0,1].scatter(datingDataType2[:,0], datingDataType2[:,1], s = 30, c = 'green')
    axs[1,0].scatter(datingDataType3[:,0], datingDataType3[:,1], s = 40, c = 'blue')
    type1 = axs[1,1].scatter(datingDataType1[:,0], datingDataType1[:,1], s = 20, c = 'red')
    type2 = axs[1,1].scatter(datingDataType2[:,0], datingDataType2[:,1], s = 30, c = 'green')
    type3 = axs[1,1].scatter(datingDataType3[:,0], datingDataType3[:,1], s = 40, c = 'blue')
    axs[1,1].legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2)
    axs[1,1].set_xlabel("玩視頻遊戲所耗時間百分比")
    axs[1,1].set_ylabel("每周消費的冰淇淋公斤數")

    plt.show()
    
    
    
def datingClassTest():
    hoRatio = 0.20  
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file
    normMat = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:,:],datingLabels[numTestVecs:],3)
        if (classifierResult != datingLabels[i]): 
            errorCount += 1.0
    print ("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print (errorCount)
    
    
datingDataMat, datingLabels = file2matrix("datingTestSet2.txt")

drawScatter1(datingDataMat, datingLabels)
drawScatter2(datingDataMat, datingLabels)
drawScatter3(datingDataMat, datingLabels)
 
datingClassTest()

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

組件設計 —— 重新認識受控與非受控組件

重新定義受控與非受控組件的邊界

對非受控組件與受控組件作了如圖中下劃線的邊界定義。一經推敲, 該定義是缺乏了些完整性嚴謹性的, 比如針對非表單組件(彈框、輪播圖)如何劃分受控與非受控的邊界? 又比如非受控組件是否真的如文案上所說的數據的展示與變更都由 dom 自身接管呢?

在非受控組件中, 通常業務調用方只需傳入一個初始默認值便可使用該組件。以 Input 組件為例:

// 組件提供方
function Input({ defaultValue }) {
  return <input defaultValue={defaultValue} />
}

// 調用方
function Demo() {
  return <Input defaultValue={1} />
}

在受控組件中, 數值的展示與變更則分別由組件的 statesetState 接管。同樣以 Input 組件為例:

// 組件提供方
function Input() {
  const [value, setValue] = React.useState(1)
  return <input value={value} onChange={e => setValue(e.target.value)} />
}

// 調用方
function Demo() {
  return <Input />
}

有意思的一個問題來了, Input 組件到底是受控的還是非受控的? 我們甚至還可以對代碼稍加改動成 <Input defaultValue={1} /> 的最初調用方式:

// 組件提供方
function Input({ defaultValue }) {
  const [value, setValue] = React.useState(defaultValue)
  return <input value={value} onChange={e => setValue(e.target.value)} />
}

// 調用方
function Demo() {
  return <Input defaultValue={1} />
}

儘管此時 Input 組件本身是一個受控組件, 但與之相對的調用方失去了更改 Input 組件值的控制權, 所以對調用方而言, Input 組件是一個非受控組件。值得一提的是, 以非受控組件的使用方式去調用受控組件是一種反模式, 在下文中會分析其中的弊端。

如何做到不管對於組件提供方還是調用方 Input 組件都為受控組件呢? 提供方讓出控制權即可, 調整代碼如下:

// 組件提供方
function Input({ value, onChange }) {
  return <input value={value} onChange={onChange} />
}

// 調用方
function Demo() {
  const [value, setValue] = React.useState(1)
  return <Input value={value} onChange={e => setValue(e.target.value)} />
}

經過上述代碼的推演后, 概括如下: 受控以及非受控組件的邊界劃分取決於當前組件對於子組件值的變更是否擁有控制權。如若有則該子組件是當前組件的受控組件; 如若沒有則該子組件是當前組件的非受控組件。

職能範圍

基於調用方對於受控組件擁有控制權這一認知, 因此受控組件相較非受控組件能賦予調用方更多的定製化職能。這一思路與軟件開發中的有異曲同工之妙, 同時讓筆者受益匪淺的 也是類似的思想。

藉助受控組件的賦能, 以 Input 組件為例, 比如調用方可以更為自由地對值進行校驗限制, 又比如在值發生變更時執行一些額外邏輯。

// 組件提供方
function Input({ value, onChange }) {
  return <input value={value} onChange={onChange} />
}

// 調用方
function Demo() {
  const [value, setValue] = React.useState(1)
  return <Input value={value} onChange={e =>
    // 只支持數值的變更
    if (/\D/.test(e.target.value)) return
    setValue(e.target.value)}
  />
}

因此綜合基礎組件擴展性通用性的考慮, 受控組件的職能相較非受控組件更加寬泛, 建議優先使用受控組件來構建基礎組件。

反模式 —— 以非受控組件的使用方式調用受控組件

首先何謂反模式? 筆者將其總結為增大隱性 bug 出現概率的模式, 該模式是最佳實踐的對立經驗。如若使用了反模式就不得不花更多的精力去避免潛在 bug。官網對反模式也有很好的。

緣何上文提到以非受控組件的使用方式去調用受控組件是一種反模式? 觀察 Input 組件的第一行代碼, 其將 defaultValue 賦值給 value, 這種將 props 賦值給 state 的賦值行為在一定程度上會增加某些隱性 bug 的出現概率。

比如在切換導航欄的場景中, 恰巧兩個導航中傳進組件的 defaultValue 是相同的值, 在導航切換的過程中便會將導航一中的 Input 的狀態值帶到導航二中, 這顯然會讓使用方感到困惑。

// 組件提供方
function Input({ defaultValue }) {
  // 反模式
  const [value, setValue] = React.useState(defaultValue);
  React.useEffect(() => {
    setValue(defaultValue);
  }, [defaultValue]);
  return <input value={value} onChange={e => setValue(e.target.value)} />;
}

// 調用方
function Demo({ defaultValue }) {
  return <Input defaultValue={defaultValue} />;
}

function App() {
  const [tab, setTab] = React.useState(1);
  return (
    <>
      {tab === 1 ? <Demo defaultValue={1} /> : <Demo defaultValue={1} />}
      <button onClick={() => (tab === 1 ? setTab(2) : setTab(1))}>
        切換 Tab
      </button>
    </>
  );
}

如何避免使用該反模式同時有效解決問題呢? 官方提供了兩種較為優質的解法, 將其留給大家作為思考。

  1. 方法一: (更為推薦)
  2. 方法二:

歡迎關注

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

windows搭建MongoDB副本集及開啟身份驗證

MongoDB副本集搭建

我搭建的是一個主節點,兩個副節點

  1. 構建目錄結構如下圖所示

  2. rs0是副本集名稱,每一份文件都是一個端口服務,以27018為主節點。

 

每一份的目錄結構如下,conf存放的是配置文件信息,data27018是存放數據庫數據信息,keyfile是存放key文件的。用於各個節點之間的身份驗證。log存放數據庫的日誌信息,用來排查問題。

 

  3.conf文件

Conf是放配置文件

# mongod.conf

# for documentation of all options, see:

#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.

storage:

  dbPath: D:\MongoDB\rs0\27018\data27018

  journal:

    enabled: true

#  engine:

#  mmapv1:

#  wiredTiger:

# where to write logging data.

systemLog:

  destination: file

  logAppend: true

  path:  D:\MongoDB\rs0\27018\log27018\mongo.log

# network interfaces

net:

  port: 27018

  bindIp: 0.0.0.0

#processManagement:

security:

  authorization: enabled

  keyFile: D:\MongoDB\rs0\27018\keyfile\replicaSet1.key

#operationProfiling:

replication:

  oplogSizeMB: 2048

  replSetName: rs0

#sharding:

  #clusterRole: shardsvr

## Enterprise-Only Options:

#auditLog:

#snmp:

4.Keyfile下有個.key的文件為了複製集的用戶驗證。(keyfile文件是需要base編碼且差不多660個字符。權限)

可用Linux系統生成,或者找度娘。每一個端口服務下的key必須是同一個。

5.修改每一個實例的conf文件里的端口號及數據存放地址,日誌等。

6.運行win+r 選擇管理員啟動cmd

Windows註冊服務

Windows註冊服務
mongod.exe --config "D:\MongoDB\rs0\27018\conf\mongo.conf" --serviceName "MongoDB27018" --serviceDisplayName "MongoDB27018" –install

mongod.exe --config "D:\MongoDB\rs0\27019\conf\mongo.conf" --serviceName "MongoDB27019" --serviceDisplayName "MongoDB27019" –install

mongod.exe --config "D:\MongoDB\rs0\27020\conf\mongo.conf" --serviceName "MongoDB27020" --serviceDisplayName "MongoDB27020" --install

安裝成服務后可以到服務中查看。

 7.註冊完成后,將所有服務啟動

8.重新打開cmd  連接到其中的一個mongodb實例命令為:   mongo –host ip地址 –port 27018

9.再連接其他兩個實例

10.進入27018節點進行初始化配置

輸入命令

其中的localhost 應是本機的IP地址。(此處坑,如果是服務器上一定要設置為IP地址,否則會重頭再來)

rscongfig={"_id":"rs0",members:[{_id:0,host:"localhost:27018"},{_id:1,host:"localhost:27019"},{_id:2,host:"localhost:27020"}]}

 

 

 

 

初始化該配置

rs.initiate(rscongfig)

回車如下圖,“ok”:1,無錯誤信息。為正確

 

 

 

看下當前節點是否為主節點

 

rs.status()查看當前副本集狀態

 

 

 

health:1   //1表明狀態是正常,0表明異常
state:1     // 1表明是primary,2表明是slave,即做備份的機器

到此副本集就搭建成功了。接下來是開啟身份驗證

11.創建用戶名

連接到27018,運行

use admin

定位到admin數據庫,在這裏創建用戶信息

db.createUser(
  {
    user: "root",
    pwd: "root",
    roles: [ { role: "root", db: "admin" } ]
  }
)  

12.找到主庫的配置文件 conf 開啟身份驗證,同時從庫也要開,配置好位置。

 

 

 

 

conf 配置好后,將服務重新啟動,然後客戶端重新連接后 如果查看等報錯的話就會提示需要權限,

然後轉到use admin

db.auth(“admin”,”admin”)輸入用戶名密碼

 返回1就是 成功。

然後登陸從節點進行登陸看一下是否需要提示。
如果都成功,可以寫入數據看一下複製集中是否有數據。

到此副本集身份驗證開啟說完了,下面說一下Springboot連接帶安全認證的複製集

application-dev.properties
spring.data.mongodb.uri=mongodb://admin:password@127.0.0.1:27018,127.0.0.1:27019,127.0.0.1:27020/ecis?authSource=admin&authMechanism=SCRAM-SHA-1&replicaSet=rs0& connectTimeoutMS=30000

//解釋
admin:password是用戶名密碼 @IP地址端口號 authSource=admin 用戶名存在的數據庫 authMechanism 不造啥意思 replicaSet 複製集名稱 connectTimeoutMS=30000連接時間

下面是navicat連接複製集方式

 

 添加主機名,端口號,點擊發現,可以查詢當前複製集中的端口服務。

 

終於寫完了,第一次寫,寫的不好,請見諒。

 

 

 

 

 

 

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

SpringBoot 配置文件與依賴庫分離打包配置

一、應用場景

一般情況下我們對springboot應用打包時使用springboot的maven插件spring-boot-maven-plugin的maven進行打包,打包完成得到一個fatjar,fatjar的優點是可以直接運行,缺點是體積太大,不利於傳輸,springboot應用打出來的fatjar體積少則幾十M,多則上百M,在往服務器部署傳輸時十分不便,可能只改了某個類文件,都需要重新將整個fatjar重新傳輸一次,特別是走公網傳輸的時候,可能上傳速度只有幾百甚至幾十KB,而整個fatjar中真正我們項目的代碼文件可能也就幾百KB或幾兆的大小,所以有必要將fatjar中的依賴庫與我們項目的class進行分離打包,這樣每次更換項目class就方便很多,而將配置文件也分離出來的原因在於我們可能經常需要更改配置文件的內容,如果放在fatjar中這樣修改是非常不方便的,所以也需要將配置文件也分離出來。

 >  fatjar 即將項目需要的所有依賴庫及配置文件等打進一個jar或war,該文件可直接運行

 

二、配置

2.1 POM配置

下面對pom.xml進行配置,來實現分離打包,配置如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>chenyb</groupId>
    <artifactId>demo</artifactId>
    <version>v1.2-release</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- springboot 打包插件 -->
            <!--
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.xx.xx</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            -->

            <!-- maven 打包插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <!-- MANIFEST.MF 中 Class-Path 加入前綴 -->
                            <classpathPrefix>lib/</classpathPrefix>
                            <!-- jar包不包含唯一版本標識 -->
                            <useUniqueVersions>false</useUniqueVersions>
                            <!-- 指定入口類 -->
                            <mainClass>cn.test.DemoApplication</mainClass>
                        </manifest>
                    </archive>
                    <outputDirectory>${project.build.directory}</outputDirectory>
                </configuration>
            </plugin>

            <!-- 拷貝依賴 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            <overWriteReleases>true</overWriteReleases>
                            <overWriteSnapshots>true</overWriteSnapshots>
                            <overWriteIfNewer>true</overWriteIfNewer>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

</project>

關鍵配置說明:

(1) 去掉了spring-boot-maven-plugin打包插件

(2) 添加 maven-jar-plugin (maven標準打包插件)

(3) maven-dependency-plugin(依賴拷貝插件,主要用於將maven依賴庫拷貝出來)

插件具體的配置,pom.xml中已添加備註說明

 

2.2 打包

執行maven package 命令進行打包,得到的結果如下

 將 lib目錄 及 項目jar 文件拷貝到同一目錄下,我為了測試方便,先全部拷貝到桌面上,(放置服務器上時也需保證在同一目錄下)

 打開demo-v1.2-release可以看到,並沒有將依賴jar打進來,大小隻有不到4KB

 

2.3 config目錄創建

以上做完還還需要將項目配置文件拷貝出來,在與jar包平級目錄建立config目錄,將項目中的application.properties或yaml文件拷貝進來

  config 下的文件

經過以上步驟,全部配置完畢,下面進行一下簡單的測試

 

三、測試

 為了保證加載的是外部config目錄的配置文件,我將application-test.yaml中的server.port改為8085, 打開命令行輸入

C:\Users\Administrator\Desktop>java -jar -Dspring.profiles.active=dev -Dspring.location.config=config/ C:\Users\Administrator\Desktop\demo-v1.2-release.jar

回車運行,能正常啟動說明外部依賴可以正常加載進來

 可以看到啟動完成后tomcat監聽端口為8085,說明外部配置加載成功。

PS : 如果外部配置文件加載失敗,會使用項目jar中的配置文件,如下圖,也就是啟動後會是8080端口

application-dev.yaml中配置的端口是8080

 

而我已將外部config目錄下application-dev.yaml中端口做了修改,使用外部配置文件啟動後會是8085端口

 

四、一點小坑

默認情況下window命令行打開后,是在當前用戶目錄下,像這樣

 而我的config、lib、項目jar拷貝在桌面上,實際路徑是

一開始我在  C:\Users\Administrator> 直接執行下方命令,一直加載不到配置文件

java -jar -Dspring.profiles.active=dev -Dspring.location.config=config/ C:\Users\Administrator\Desktop\demo-v1.2-release.jar

原因就在於程序與配置文件不在同一目錄下,我在C:\Users\Administrator>運行啟動命令,而程序實際目錄在 C:\Users\Administrator\Desktop> 下,因為程序使用了絕對路徑,可以找到文件,所以程序的實際運行路徑為C:\Users\Administrator\Desktop,而我使用的配置 spring.location.config=config/ 使用的是相對路徑,,這個相對路徑又是相對 C:\Users\Administrator> 目錄,所以就會出現找不到配置文件的情況。

 

解決辦法一:

命令行切換到 C:\Users\Administrator\Desktop 目錄,即項目jar所在目錄,運行 java -jar 命令

 

解決辦法二:

將config拷貝到C:/Users/Administrator下,保證C:/Users/Administrator相對路徑下存在config目錄及配置文件(該方法可解決問題,但是不建議)

 

解決方法三:

spring.location.config=config/ 處使用絕對路徑,即C:/Users/Administrator/Desktop/config/ 

 

所以很重要一點,一定保證 執行命令 的目錄 與項目jar、lib、config都在同一目錄下。

 

五、完整demo地址

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

人臉識別技術原理與工程實踐(10個月人臉識別領域實戰總結)

1人臉識別應用場景(驗證)

我們先來看看人臉識別的幾個應用。第一個是蘋果的FACE ID,自從蘋果推出FaceID后,業界對人臉識別的應用好像信心大增,各種人臉識別的應用從此開始“野蠻生長”。

事實上,人臉識別技術在很多場景的應用確實可以提升認證效率,同時提升用戶體驗。前兩年,很多機場安檢都開始用上了人臉驗證;今年4月,很多一、二線城市的火車站也開通了“刷臉進站”的功能;北京的一些酒店開始使用人臉識別技術來做身份驗證。

 

2 人臉識別應用場景(識別)

我們再來看看幾個場景。

 

第一個是刷臉的自動售貨機。當我第一次看到這個機器的時候就有個疑問:”現在人臉識別算法已經做到萬無一失了嗎,認錯人,扣錯錢怎麼辦?”,後來才發現,其實關鍵不在於算法,產品設計才是最重要的。用過這個售貨機的人可能知道,第一次使用的時候,要求輸入手機號的后四位,這個看似簡單的產品設計,可以讓自動售貨機的誤識別率降低到億分之一,這樣底概率的條件下,誤識別帶來的損失完全可以忽略。同時這款自動售貨機還會提醒你,你的消費行為會綁定“芝麻信用”,想想有幾個人會為了一瓶“可樂”去影響自己的徵信記錄呢?

第二個是刷臉買咖啡,進入咖啡店后,在你選好喝什麼咖啡前,系統已經識別出站在點單台前的用戶是誰,並做好點單準備;

第三個是在人臉門禁系統。小夥伴們再已不用擔心忘記帶工卡了。人臉門禁對識別速度和準確度的要求是相對較高的,設備掛在門的側面牆也會影響體驗,增加產品設計和開發的難度。

 

3 “人臉驗證”還是“人臉識別”?

其實,前面兩頁的場景是有些區別的,不知道大家看出來了沒有。

第一個的場景,用戶實際提供了兩個信息,一是用戶的證件信息,比如身份證號碼,或APP賬號;另一個信息是用戶的現場照片;這類場景的目標實際上是:讓人臉識別系統驗證現場照片是否是證件所宣稱的那個人。我們把這類場景叫着“人臉驗證”

第二個的場景,用戶實際只提供的現場照片,需要人臉識別系統判斷照片上的人是誰。我們把這類場景叫着“人臉識別”

“人臉驗證”拿現場人臉跟用戶所宣稱的人臉做1比1的比較,而“人臉識別”是拿現場人臉跟後台註冊人臉庫中的所有人臉比較,是1比N的搜索。可以看出,兩種場景的技術原理一致,但是難度不同,第二頁場景的難度普遍比第一頁高得多。

 

4 人臉識別原理

計算機是怎麼識別人臉的呢?如果我們大家是人臉識別系統的設計者,我們應用怎樣來設計這個系統?

“把人臉區域從圖片中摳出來,然後拿摳出來的人臉跟事先註冊的人臉進行比較”,沒錯,就是這樣,說起來簡單,做又是另外一回事了,這裏又有兩個新的問題:

一是,“怎樣判斷圖片中是有沒有人臉?”,“怎樣知道人臉在圖片中的具體位置呢”,這是人臉檢測要解決的問題,人臉檢測告訴我們圖像中是否有人臉以及人臉的具體位置坐標。

二是,“我們怎樣比較兩個人臉是不是同一個人呢?”,一個像素一個像素比較嗎?光照,表情不一致,人臉偏轉都將導致該方法不可行。”人是怎樣判斷兩種照片中的人臉是不是同一個人的呢?”,我們是不是通過比較兩種照片上的人,是不是高鼻樑、大眼睛、瓜子臉這樣的面部特徵來做判斷的呢? 

我們來看一下計算機人臉識別的流程,首先是獲取輸入圖像,然後檢測圖像中是否有人臉,人臉的具體位置,然後判斷圖像的質量,比如圖像是否模糊,光照度是否足夠,然後檢測人臉偏轉的角度,旋轉人臉到一個正臉位置,再然後提取人臉特徵,比對人臉特徵,最後輸出識別結果。其中圖像質量檢測和人臉對齊這兩步是可選的步驟,根據具體應用場景來決定。

 

5 人臉檢測-經典方法

我們來看看經典的人臉檢測方法。

OpenCV和Dlib是兩個常用的算法庫。

OpenCV 中使用Haar Cascade來做人臉檢測,其實Haar Cascade可以檢測任何對象,比如人臉和臉上眼睛的位置。

DLIB中是使用方向梯度直方圖(Histogram of Oriented Gradient, HOG),即通過計算圖像局部區域的梯度方向直方圖來提取特徵,這種方法的本質在於梯度的統計信息,而梯度主要存在於邊緣的地方。

OpenCV和DLIB各自也有他們自己的基於深度學習的人臉檢測方法,使用起來非常簡單。從這幾種方法都可以做到CPU實時或GPU實時;經典的檢測方法對正臉的檢測效果比較好,深度學習的方法適應性更強,可以檢測各種角度的人臉

 

6 MTCNN人臉檢測

2016年提出來的MTCNN算法是目前公認比較好的人臉檢測算法是(Multi-task Cascaded Convolutional Networks),可以同時實現face detection和alignment,也就是人臉檢測和對齊。

這裏的對齊指的是檢測人臉眼睛、鼻子、嘴巴輪廓關鍵點LandMark。

MTCNN算法主要包含三個子網絡:P-Net (Proposal Network)、 R-Net(Refine Network)、O-Net(Output Network),這3個網絡按照由粗到細的方式處理輸入照片,每個網絡有3條支路用來分別做人臉分類、人臉框的回歸和人臉關鍵點定位

左上角,最開始對在多個尺度上對圖像做了resize,構成了圖像金字塔,然後這些不同尺度的圖像作為P、P、O網絡的輸入進行訓練,目的是為了可以檢測不同尺度的人臉

P-Net主要用來生成候選人臉框。 R-Net主要用來去除大量的非人臉框。O-Net和R-Net有點像,在R-NET基礎上增加了landmark位置的回歸,最終輸出包含一個或多個人臉框的位置信息和關鍵點信息

 

7 人臉特徵提取-經典方法

接下來,我們來看一下人臉特徵提取。經典的人臉特徵提取方法有EigenFace和FisherFace兩種。

EigenFace的思想是把人臉從像素空間變換到另一個空間,在另一個空間中做相似性的計算。EigenFace的空間變換方法是主成分分析PCA。這個方法90年代開始應用於人臉識別,因為主成分有人臉的形狀,所以也稱為“特徵臉”。

FisherFace是一種基於線性判別分析LDA(全稱Linear  Discriminant Analysis,)的人臉特徵提取算法, LDA和PCA都是利用特徵值排序找到主元的過程。LDA強調的是不同人臉的差異而不是照明條件、人臉表情和方向的變化。所以,Fisherface對人臉光照、人臉姿態變化的影響更不敏感。

 

8 人臉特徵提取-深度學習法

我們再來看看深度學習法。

利用神經網絡學習高度抽象的人臉特徵,然後將特徵表示為特徵向量,通過比較特徵向量之間的歐式距離來判定兩張照片是否是同一個人

 

9人臉特徵提取-深度學習法

總體思路是把人臉識別人物當分類任務來訓練,通過在損失函數上施加約束,讓相同的人的照片提取的特徵距離盡可能近,不是同一個人的照片的提取的特徵距離盡可能的遠

第一個Logit的地方輸出的是人臉的特徵向量,一般是128維或者512維,浮點向量。這個Logit前面是CNN分類網絡,這個Logit後面的部分是通過在損失函數上施加約束來訓練模型,讓模型區分相同的人和不同的人,後面的部分只需要在訓練階段計算,推理階段是不需要的。

 

10 人臉特徵提取-Metric Learning

基於深度學習的人臉特徵提取方法主要有兩類,一類Metric Learning,另一個是Additive Margin,這兩類方法的底層原理都是一樣的,就是“通過訓練網絡,讓相同人的特徵距離盡可能近,不同人的特徵距離盡可能的遠”。

孿生網絡和Triplet都屬於 Metric Learning這類方法。左邊孿生網絡顧名思義,就是有兩個網絡,一個網絡訓練讓相同的人之間的距離盡可能的近,另一個網絡讓不同人之間的距離盡可能遠。

右邊Triplet網絡是對孿生網絡的改進,將樣本組織為錨點、正樣本、負樣本的元組,通過訓練網絡讓錨點與正樣本之間的距離盡可能的近,錨點與負樣本之間的距離盡可能的遠,並且至少遠於一個閥值阿爾法。

 

11 人臉特徵提取-Additive Margin

Additive Margin這類方法主要是在分類模型的基礎,通過控制損失函數來達到“讓相同人的特徵距離盡可能近,讓不同人的特徵距離盡可能遠”的目標。

前面介紹的Metric Learning的方法最大的問題在於:需要重新組織樣本,模型最終能否收斂很大程度上取決於採樣是不是合理。基於Additive Margin的方法則不需要這一步,完全將人臉特徵提取當做分類任務來訓練,參數的設置也不需要太多trick,Additive Margin的方法大都是在損失函數上做文章。

最近幾年,這個類方法研究的比較多,上面這個圖中的softmax,Sphereface,Cosface,ArcFace都是Additive Margin方法,可以看出它都是通過改進損失函數,來實現“讓相同人的特徵距離盡可能近,讓不同人的特徵距離盡可能遠”這個目標

上面這個圖中,顏色相同的點表示一個人,不同的點表示不同的人,這個圖的展示比較形象,可以看出最後一個超球體的效果非常不錯

Additive Margin正在成為主流, InsightFace也屬於這一類,損失函數正是這個ArcFace。

大家可用思考一下,為什麼分類方法不能直接用於人臉識別?這裏不做詳細討論了。

 

12 人臉特徵提取-效果評估

我們再來看一下怎樣評估人臉特徵提取算法的效果。

主要是通過召回率和虛警率兩個指標來衡量。應用場景不同,這個兩個指標的設置也不同,一般情況下,在實踐中我們都要求在虛警率小於某個值(比如萬分之一)的條件下,召回率達到某個值(比如99%)。很多產品宣稱的識別準確率達到多少多少,很大可能是在公開數據集比如LFW上的測試結果。

公開的訓練數據集比較推薦的有:MS1MV2,這個數據集微軟前段事件已經宣布撤回不再提供下載,這個數據集大概有85000個不同的人的380萬張照片。另一個數據集是GLINT_ASIA,有9萬多人的280萬張照片。

 

13 工程實踐的挑戰及經驗分享

很多人都認為人臉識別應用,算法包打天下,事實並非如此,即使是最好的識別算法也扛不住像圖像質量差。圖像質量差、姿勢變化、面部形狀/紋理隨着時間推移的變化、遮擋這些問題,是我們在工程實踐中面臨的挑戰。

當然,大多數問題工程上我們有應對方法。比如圖像模糊,光照不足,我們可以先檢測圖像是否模糊,關照是否不足,質量不過關,就不把圖像送給識別算法。

再比如,用他人照片或視頻來欺騙人臉識別系統,目前已經有多種活體檢測方法來檢測並防止這種情況。

經過一段時間在人臉識別領域的摸爬滾打,個人認為影響用戶體驗的關鍵因素是識別快、識別准,識別快主要靠產品設計,識別准主要靠算法

拿人臉門禁來舉個例子,產品設計上可以在前端採集照片的時候過濾掉模糊、無人臉的照片,避免無效識別,同時前端在採集照片的時候,可以同時採集多張併發傳給後台,做併發識別,這些方法都可以大大提升識別通過的速度,提升用戶體驗。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

dbstructsync -mysql表、字段、索引差異解析工具(原創)

最近寫了一個工具(比較兩套測試環境mysql數據庫中表、表字段、索引的差異,基於python)通過文章簡單介紹下工具的相關內容

  1. 工具名稱
  2. 主要功能
  3. 具體使用方法
  4. 部分實現代碼
  5. 後續

一、工具名稱:

dbstructsync (python庫)

二、主要功能:

比較兩套環境中mysql指定庫中表、表字段及索引的差異,返回同步的sql ,裡面包含建表,修改索引,修改字段的sql .

A環境的數據庫db 作為sourcedb, B環境的數據庫db targetdb ,程序邏輯比較的是 sourcedb 與targetdb 的差異,然後返回一個list的數據類型 

list中包含新建表sql,修改、增加字段sql, 刪除、新增索引sql 

現在總共有3個版本,0.0.1 和0.0.2 存在一定的bug, 所以請使用最新的0.0.3版本

 

 

其他說明:由於是剛完成不久的程序,所以暫時不對最終結果sql進行執行,避免對使用過程中產生不好的影響,這個版本大家可以通過python 自行選擇需要執行哪些操作;隨着之後程序的逐步深入修改和演變,會將執行sql這一步也都加進去

同時也會優化使用方式,讓使用這個工具的小夥伴更容易操作

三、具體使用方法:

1、 pip install  -i https://pypi.python.org/pypi  dbstructsync   

在代碼里引入使用,

from DbStructSync import cli 

result=cli.db_sync(sourcedb, targetdb) 
#sourcedb,targetdb是兩個dict的參數,具體參數看下面
# 這裏得到的    result = ['use 庫;', 
#             'CREATE TABLE `test_async` (\n  `test_async` #varchar(30) NOT NULL,\n  `aa` varchar(400) DEFAULT NULL,\n  #PRIMARY KEY (`test_async`)\n) ENGINE=InnoDB DEFAULT #CHARSET=utf8;',
#             'drop index `index_chaxx` on chanxx_auto_puxx_conf;',
#             'create index `index_chaxx` on #chanxx_auto_puxx_conf(`channel_nxx`,`channel_prxx`) USING #BTREE;']
#result 中包含  use 庫;
#              如果有少的表,會有 create table的數據; 如果有不同的索引,會#存在drop index 和create index的sql;
#              如果有不同的字段,會有alter table的sql ;
#只需要對這個結果,再通過pymysql的一些數據庫操作就可以保證 sourcedb #的內容與taragetdb一致。

2、同時還支持命令行操作,代碼寫入到x.py代碼中

result = cli.db_sync_commandline()
python x.py --source  host=10.1.1.x,port=3306,user=root,passwd=root,db=investx --target host=10.1.1.x,port=3306,user=root,passwd=root,db=investx

 

命令行中  –source  key=value;key2=value2;key3=value3  –target key=value;key2=value2;key3=value3

–source, –target 是兩給必輸的參數,後續的值會作為一個dict類型傳入程序。 –source是源庫的信息, –target是目標庫的信息

還包括其他幾個命令參數 –only-index , –only-fields ; –only-index 只比較索引差異, –only-fields 只比較字段差異, 非必填,默認都為False 

四、部分實現代碼:

 

def diff_tables(sourcetable, targettable):
    '''

    :param sourcetable:  源數據庫的表名列表
    :param targettable:  目的數據庫的表名列表
    :return: 返回dict,包含三種結果,源庫多的表,目標庫多的表,相同的表
    '''
    logger.info('開始比較兩個庫中表的差異,源庫表{},目標庫表{}'.format(sourcetable, targettable))
    table_result={}
    if not isinstance(sourcetable, list) or not isinstance(targettable, list):
         raise  TypeError('sourcetable , targettable的類型不是list')
    source_diff = set(sourcetable) - set(targettable)
    target_diff = set(targettable) - set(sourcetable)
    same_tables = set(sourcetable)& set(targettable)
    table_result['source'] = source_diff
    table_result['target'] = target_diff
    table_result['same'] = same_tables
    logger.info('兩個庫中表的差異結果{}'.format(table_result))
    return  table_result
 

def  diff_indexs_fields(sourcesql, targetsql, type=1):
    '''
    :param sourcesql: 源數據庫表的創建sql
    :param targetsql: 目標數據表的創建sql
    :return: 記錄下索引不一致的地方
    '''
    result = {}
    logger.info('解析語句中的索引字段,並進行比較索引')
    sourcesql = parse_str(sourcesql)  # 從括號中提取需要的內容
    #logger.info('從括號中提取出來的信息數據{}'.format(sourcesql))
    sourcesql = lists2str(sourcesql)  #將list轉換為str,並對數據的空格數據進行處理
    logger.info('解析完的數據的信息{}'.format(sourcesql))
    sourcesql = sourcesql.split('\n') #將str按照'\\n'進行分割
    logger.info('解析完數據之後的信息{}'.format(sourcesql))
    targetsql = parse_str(targetsql)
    targetsql = lists2str(targetsql)
    targetsql = targetsql.split('\n')
    if type ==1:
        source_index = parse_fields(sourcesql,type)
        target_index = parse_fields(targetsql,type)

        result= compare_indexs_field(source_index, target_index, type)
    elif type ==2:
        source_field_sql = parse_fields(sourcesql, type)
        target_field_sql = parse_fields(targetsql, type)
        result = compare_indexs_field(source_field_sql, target_field_sql, type)
    return  result

def dict2sql(dict_str):
    '''
    將解析完成的數據轉換為對應的可執行sql
    :param dict_str:
    :return:
    '''
    dict_str = copy.deepcopy(dict_str) # 做一個深度copy,可以放心的進行相關數據處理

    if not isinstance(dict_str, dict):
        raise  TypeError('調用方法{}參數不是dict類型,請確認'.format('dict2sql'))
    #獲取db名字
    for key ,value in dict_str.items():
        dbname = key
        logger.info('數據庫名{}'.format(dbname))
        for table, table_desc  in  value.get('source').items():
               if table =='create_table':
                   #create_table_sql = lists2str(table_desc)
                   dict_str[dbname]['source'][table] = table_desc
                   #其他的都是table的名字
                   logger.info('數據庫的修改語句:{}'.format(table_desc))
               else:
                  logger.info('對於索引和字段的解析原始數據{}'.format(table_desc))
                  if table_desc.get('index'):
                      create_index_sql_lists=[]
                      #create_index_sql_lists.append('use {};'.format(dbname))
                      index_lists= (table_desc.get('index'))
                      result_index= parse_comma_split(str(index_lists)[1:-1])
                      for i in result_index:
                           if i.strip().startswith('\'KEY'):
                               #print(i.strip())
                               index_values = parse_space_split(i.strip())
                               drop_index_sql= 'drop index {} on {}'.format(index_values[1],table )
                               if len(index_values)<=3:
                                  create_index_sql='create index {} on {}{} '.format(index_values[1], table, index_values[2])
                               else:
                                  create_index_sql='create index {} on {}{} {}'.format(index_values[1], table, index_values[2], ' '.join(index_values[3:]))
                               create_index_sql_lists.append(drop_index_sql)
                               create_index_sql_lists.append(create_index_sql)

                           if i.strip().startswith('\'UNIQUE KEY'):
                                 index_values = parse_space_split(i.strip())
                                 drop_index_sql = 'drop index {} on {}'.format(index_values[2], table)
                                 if len(index_values) <= 4:
                                     create_index_sql = 'create unique index {} on {}{} '.format(index_values[2], table,
                                                                                          index_values[3])
                                 else:
                                     create_index_sql = 'create unique index {} on {}{} {}'.format(index_values[2], table,
                                                                                               index_values[3],
                                                                                               ' '.join(index_values[4:]),
                                                                                               )
                                 create_index_sql_lists.append(drop_index_sql)
                                 create_index_sql_lists.append(create_index_sql)
                      logger.info('表{}解析出來的索引的修改sql{}'.format(table, create_index_sql_lists))
                      dict_str[dbname]['source'][table]['index'] = create_index_sql_lists
                  if table_desc.get('fields'):
                      create_fields_sql_lists=[]
                      #create_fields_sql_lists.append('use {};'.format(dbname))
                      modify_field_sqls = table_desc.get('fields').get('modify',None)
                      create_field_sqls=table_desc.get('fields').get('lose',None)

                      if modify_field_sqls:
                           for modify_field_sql in modify_field_sqls:
                               sql_indexs = parse_space_split(str(modify_field_sql)[0:-1])
                               #print(sql_indexs)
                               alter_fields_sql='alter table {} modify column {} {} {}'.format(table, sql_indexs[0],sql_indexs[1],' '.join(sql_indexs[2:]))
                               create_fields_sql_lists.append(alter_fields_sql)
                      if create_field_sqls:
                           for  create_field_sql in create_field_sqls:
                                sql_indexs = parse_space_split(str(create_field_sql)[0:-1])
                                create_fields_sql='alter table {} add column {} {}'.format(table, sql_indexs[0],' '.join(sql_indexs[2:]))
                                create_fields_sql_lists.append(create_fields_sql)
                      logger.info('表{}解析出來的字段的修改sql{}'.format(table,create_fields_sql_lists))
                      dict_str[dbname]['source'][table]['fields'] = create_fields_sql_lists

    return  dict_str  # 返回給一個全部是可執行sql的dict

五、後續:

1、對使用過程中遇到對bug進行修復

2、對代碼進行優化

3、增加其他相關功能,讓工具越來越好用

4、希望使用的小夥伴多提意見,未來成為一個好用的小工具

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

松下預計提高美國電池廠年產能以供特斯拉需求

日經亞洲評論28日報導,松下(Panasonic)汽車零件部門執行副總伊藤好生(Yoshio Ito)在受訪時表示,車用電池能量密度越來越高、處理的難度也跟著升高,松下不能將電池賣給沒有能力肩負起產品安全控管能力的電動車製造商。他說,從需求的角度來看、電動車電池銷售額要倍增不是件難事,但在考量合格工程師人數、土地、廠房以及主管機關許可執照等因素後松下決定不去追求不切實際的目標。

伊藤指出,松下已經決定將美國電池廠年產能提升至35 GWh、現階段並無進一步擴產的明確規劃。作為特斯拉(Tesla)的獨家電池供應商,松下的任務就是供應足夠的數量給客戶。他還提到,松下計畫開發雷達和聲納技術、聚焦自駕車市場中現有車商忽視的利基需求。

官網資料顯示,2020年特斯拉超級電池工廠(Gigafactory)的年產能將超過2013年全球鋰電池產能的總和。

華爾街日報7月15日報導,加州下議院已通過規模達30億美元的電動車購車退稅折扣法案,後續還得過上議院與州長Jerry Brown這兩關。

負責起草這項法案的舊金山民主黨籍議員Phil Ting表示,加州若想落實氣候變遷目標(2025年讓150萬輛零排放車輛上路)、勢必得想辦法給電動車產業打強心針才行。根據加州空氣資源局的統計,加州已有超過25萬輛零排放汽車(包括電動車)上路、佔美國約半數的比重。

特斯拉平價電動車「Model 3」售價為35,000美元起(不含獎勵計畫)、電池續航力為345公里。特斯拉在6月23日創下歷史收盤新高紀錄(383.45美元)、7月28日以335.07美元坐收。

(本文內容由授權使用。圖片出處:Tesla)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

車拚鋰電池!鹼性電池新突破 可重複充電、以鋁代鋅

 

鹼性電池售價便宜、也比鋰電池更不容易起火燃燒,唯一缺點是無法重複充電使用。不過,新創公司Ionic Materials即將在本週四(8月3日)發表一項突破性的新發現,讓固態的鹼性電池成為鋰電池等高儲電科技的替代品,直接應用到PC、智慧型手機或電動車。

紐約時報1日報導(),Ionic發明的新技術,可讓鹼性電池重複充電,其推出的原型,最多已能充電400次。Ionic創辦人兼材料科學家Mike Zimmerman說,該公司開發的鹼性電池,目前雖比市面上的鋰電池還要重,但其成本優勢和更優秀的儲電能力,將彌補這項缺點。

不只如此,鋰電池的關鍵材料是鈷,不但毒害環境,非洲還有不少礦場違法使用童工採鈷,令人憂心。相較之下,鹼性電池使用的是蘊藏量相對豐富的鋅和錳。

另外,Ionic還修正鹼性電池的設計,以價格更為親民的鋁取代鋅。在過去,鋁因為容易被腐蝕的問題,並未被採納,若鹼性電池真的能以鋁為材料,那麼重量有機會比鋰電池還要輕,也會比當前市面上的鹼性電池還要便宜。

報導稱,Ionic計畫在週四於永續能源研究機構Rocky Mountain Institute舉行的35週年大會上,宣布研究成果。

鹼性電池若能重複充電、將有諸多好處,但鋰電池之父John Goodenough也不是省油的燈。Goodenough雖已高齡94歲,卻寶刀未老,他今(2017)年3月已經帶領德州大學(University of Texas)奧斯汀分校團隊,打造出「全固態」(all-solid-state)鋰電池,不但更加安全,容量還是三倍大,而且只要數分鐘就可充電完畢,不必再像從前那樣等待數小時。

Apple Insider、CNET、CleanTechnica等多家外電3月6日報導,Goodenough採用全新技術打造的鋰電池可適用幾乎所有裝置,包括iPhone、MacBook Pro、車用電池或是類似特斯拉「Powerwall」家用電力儲存系統等,都可使用這種電池。

Goodenough團隊開發的最新技術,使用了玻璃製的電解質(不是以往的液體 ),可解決電池充電過快時激發「金屬鬚晶」(metal whiskers),導致正負兩極相互接觸、繼而起火爆炸的問題。

玻璃電解質是以鋰、鈉或鉀製成,可大幅增加電池的能量密度,據研究人員估算,即使充放電超過1,200次,電池續航力也幾乎不受影響。不僅如此,即使環境急凍到零下20度C,新款電池依舊能正常運作。

研發團隊指出,玻璃電解質可簡化電池製造流程,採用的材料也都對環境友善,能輕鬆回收再利用,另外更能降低稀土金屬的使用量。不過,德州大學科技商業化辦公室目前還在跟多家電池大廠洽談授權事宜,因此短期內恐怕還無法上市。

(本文內容由授權使用。圖片出處:Ionic Materials)  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象