python去噪
① python繪折線圖(數據很多)很難看
數據使用前要清洗,去除無效數據。
如果這些數據都是有效數據,只是你不想顯示那些過份異常的數據,那麼,就進行去噪處理。
去噪分兩步:檢測噪點,噪點修正。
對於整體連續,總體范圍大的數據集,最簡單的檢測噪點的辦法就是鄰值法,對於第n取相鄰的k個值:p[n-k,],p[n-k+1]...p[n-1]
對它們加權平均,得到標准點,上下浮動一定范圍,如果p[k]不在這個范圍內就是異常點
對應的噪點修正可以使用類似的過程,局部噪點回歸法。
這些一般來說都不是很實現的東西,對於數據集結構的不同,沒有必要做成通用的包,所以你只有自己實現。
② 怎樣用python實現圖像去噪
#coding:utf-8
importsys,os
fromPILimportImage,ImageDraw
#二值數組
t2val={}
deftwoValue(image,G):
foryinxrange(0,image.size[1]):
forxinxrange(0,image.size[0]):
g=image.getpixel((x,y))
ifg>G:
t2val[(x,y)]=1
else:
t2val[(x,y)]=0
#降噪
#根據一個點A的RGB值,與周圍的8個點的RBG值比較,設定一個值N(0<N<8),當A的RGB值與周圍8個點的RGB相等數小於N時,此點為噪點
#G:Integer圖像二值化閥值
#N:Integer降噪率0<N<8
#Z:Integer降噪次數
#輸出
#0:降噪成功
#1:降噪失敗
defclearNoise(image,N,Z):
foriinxrange(0,Z):
t2val[(0,0)]=1
t2val[(image.size[0]-1,image.size[1]-1)]=1
forxinxrange(1,image.size[0]-1):
foryinxrange(1,image.size[1]-1):
nearDots=0
L=t2val[(x,y)]
ifL==t2val[(x-1,y-1)]:
nearDots+=1
ifL==t2val[(x-1,y)]:
nearDots+=1
ifL==t2val[(x-1,y+1)]:
nearDots+=1
ifL==t2val[(x,y-1)]:
nearDots+=1
ifL==t2val[(x,y+1)]:
nearDots+=1
ifL==t2val[(x+1,y-1)]:
nearDots+=1
ifL==t2val[(x+1,y)]:
nearDots+=1
ifL==t2val[(x+1,y+1)]:
nearDots+=1
ifnearDots<N:
t2val[(x,y)]=1
defsaveImage(filename,size):
image=Image.new("1",size)
draw=ImageDraw.Draw(image)
forxinxrange(0,size[0]):
foryinxrange(0,size[1]):
draw.point((x,y),t2val[(x,y)])
image.save(filename)
image=Image.open("d:/1.jpg").convert("L")
twoValue(image,100)
clearNoise(image,4,1)
saveImage("d:/5.jpg",image.size)
③ python pil 怎麼去掉驗證碼線條
一、驗證碼識別的概念
機器識別圖片主要的三個步驟為消去背景、切割字元、識別字元。而現有的字元驗證碼也針對這三個方面來設計強壯的驗證碼。
以下簡圖幫助大家理解驗證碼識別的流程:
二、處理流程
其中最為關鍵的就是好圖像處理這一步了。圖像處理功能模塊包括圖像的灰度化、二值化、離散雜訊點的去除、傾斜度校正、字元的切割、圖像的歸一化等圖像處理技術 。
1、 圖像的灰度化
由於 256 色的點陣圖的調色板內容比較復雜,使得圖像處理的許多演算法都沒有辦法展開,因此有必要對它進行灰度處理。所謂灰度圖像就是圖像的每一個像素的 R、G、B 分量的值是相等的。彩色圖像的每個像素的 R、G、B 值是不相同的,所以顯示出紅綠藍等各種顏色。灰度圖像沒有這些顏色差異,有的只是亮度上的不同。灰度值大的像素點比較亮(像素值最大為 255,為白色),反之比較暗(像素值最小為 0,為黑色)。圖像灰度化有各種不同的演算法,比較直接的一種就是給像素的 RGB 值各自一個加權系數,然後求和;同時還要對調色板表項進行相應的處理。
2、 圖像的二值化
要注意的是,最後得到的結果一定要歸一到 0-255 之內。因為這是每個位元組表示
圖像數據的極限。
3、 去噪
圖像可能在生成、傳輸或者採集過程中夾帶了雜訊,去雜訊是圖像處理中常用的手法。通常去雜訊用濾波的方法,比如中值濾波、均值濾波。但是那樣的演算法不適合用在處理字元這樣目標狹長的圖像中,因為在濾波的過程中很有可能會去掉字元本身的像素。
一個採用的是去除雜點的方法來進行去雜訊處理的。具體演算法如下:掃描整個圖像,當發現一個黑色點的時候,就考察和該黑色點間接或者直接相連接的黑色點的個數有多少,如果大於一定的值,那就說明該點不是離散點,否則就是離散點,把它去掉。在考察相連的黑色點的時候用的是遞歸的方法。此處,我簡單的用python實現了,大家可以參考以下。
#coding=utf-8"""
creat time:2015.09.14
"""import cv2import numpy as npfrom matplotlib import pyplot as pltfrom PIL import Image,ImageEnhance,ImageFilter
img_name = '2+.png'#去除干擾線im = Image.open(img_name)#圖像二值化enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
data = im.getdata()
w,h = im.size#im.show()black_point = 0for x in xrange(1,w-1): for y in xrange(1,h-1):
mid_pixel = data[w*y+x] #中央像素點像素值
if mid_pixel == 0: #找出上下左右四個方向像素點像素值
top_pixel = data[w*(y-1)+x]
left_pixel = data[w*y+(x-1)]
down_pixel = data[w*(y+1)+x]
right_pixel = data[w*y+(x+1)] #判斷上下左右的黑色像素點總個數
if top_pixel == 0:
black_point += 1
if left_pixel == 0:
black_point += 1
if down_pixel == 0:
black_point += 1
if right_pixel == 0:
black_point += 1
if black_point >= 3:
im.putpixel((x,y),0) #print black_point
black_point = 0im.show()041424344
原驗證碼:
4、分割
圖像中一般會含有多個數字,識別的時候只能根據每個字元的特徵來進行判斷,所以還要進行字元切割的工作。這一步工作就是把圖像中的字元獨立的切割出來。
具體的演算法如下:
第一步,先自下而上對圖像進行逐行掃描直至遇到第一個黑色的像素點。記錄下來。然後再自上而下對圖像進行逐行掃描直至找到第一個黑色像素,這樣就找到圖像大致的高度范圍。
第二步,在這個高度范圍之內再自左向右逐列進行掃描,遇到第一個黑色像素時認為是字元切割的起始位置,然後繼續掃描,直至遇到有一列中沒有黑色像素,則認為這個字元切割結束,然後繼續掃描,按照上述的方法一直掃描直至圖像的最右端。這樣就得到了每個字元的比較精確寬度范圍。
第三步,在已知的每個字元比較精確的寬度范圍內,按照第一步的方法,分別進行自上而下和自下而上的逐行掃描來獲取每個字元精確的高度范圍。
5、 圖像的歸一化
因為採集的圖像中字元大小有可能存在較大的差異,或者是經過切割後的字元尺寸不統一,而相對來說,統一尺寸的字元識別的標准性更強,准確率自然也更高,歸一化圖像就是要把原來各不相同的字元統一到同一尺寸,在系統實現中是統一到同一高度,然後根據高度來調整字元的寬度。具體演算法如下:先得到原來字元的高度,跟系統要求的高度做比較,得出要變換的系數,然後根據得到的系數求得變換後應有得寬度。在得到寬度和高度之後,把新圖像裡面的點按照插值的方法映射到原圖像中。
不少人認為把每個字元圖像歸一化為 5×9 像素的二值圖像是最理想的,因為圖像的尺寸越小,識別速度就越高,網路訓練也越快。而實際上,相對於要識別的字元圖像, 5×9 像素圖太小了。歸一化後,圖像信息丟失了很多,這時進行圖像識別,准確率不高。實驗證明,將字元圖像歸一化為 10×18 像素的二值圖像是現實中是比較理想的,達到了識別速度快和識別准確率高的較好的平衡點。
三、識別
圖像識別包括特徵提取、樣本訓練和識別三大塊內容。
驗證碼識別其中最為關鍵的就是去噪和分割,這對你的訓練和識別的精度都有著很大的影響。這里只講了大致的流程,其中每個細節都有很多工作要做,這里碼字也很難講清楚,大家可以以這個流程為主線,一步步的實現,最終也就能完成你的需求。
④ python里的問題 ,pywt.dwt(signal,'db1','sym')這個函數
雜訊能獲取嗎?好吧。你可以試試減一減。不過你的測試用例不太對。 盡量用有規律的數據去做。
比如你可以做一個正弦函數,再人為的加上一點點擾動。再做小波變換看看。另外數據要多些。太短的數據看不出效果來。
至於變換後是兩個4,我想等你數據弄多些就明白了。 數據多些,就容易做圖。你把變換後的數據變成圖形,畫出來。可以用EXCEL來畫。
這樣一對比就明白變換後的兩個4數組是什麼數據。 然後你就可以針對性的處理。取得雜訊也是可以的。
通常來講雜訊是沒有規律的。 但是不排除它是另外一種規律迭加上去的。 試試看。
⑤ python sklearn主成分分析法 各個特徵向量是啥意思
主成分分析(PCA)是一種基於變數協方差矩陣對數據進行壓縮降維、去噪的有效方法。
PCA的思想是將n維特徵映射到k維上(k<n),這k維特徵稱為主元,是舊特徵的線性組合,這些線性組合最大化樣本方差,盡量使新的k個特徵互不相關。
⑥ 聲線年齡層怎麼劃分
從EDA、音頻預處理到特徵工程和數據建模的完整源代碼演示
大多數人都熟悉如何在圖像、文本或表格數據上運行數據科學項目。 但處理音頻數據的樣例非常的少見。 在本文中,將介紹如何在機器學習的幫助下准備、探索和分析音頻數據。 簡而言之:與其他的形式(例如文本或圖像)類似我們需要將音頻數據轉換為機器可識別的格式。
音頻數據的有趣之處在於您可以將其視為多種不同的模式:
· 可以提取高級特徵並分析表格數據等數據。
· 可以計算頻率圖並分析圖像數據等數據。
· 可以使用時間敏感模型並分析時間序列數據等數據。
· 可以使用語音到文本模型並像文本數據一樣分析數據。
在本文中,我們將介紹前三種方法。 首先看看音頻數據的實際樣子。
音頻數據的格式
雖然有多個 Python 庫可以處理音頻數據,但我們推薦使用 librosa。 讓我們載入一個 MP3 文件並繪制它的內容。
# Import librosa
import librosa
# Loads mp3 file with a specific sampling rate, here 16kHz
y, sr = librosa.load("c4_sample-1.mp3", sr=16_000)
# Plot the signal stored in 'y'
from matplotlib import pyplot as plt
import librosa.display
plt.figure(figsize=(12, 3))
plt.title("Audio signal as waveform")
librosa.display.waveplot(y, sr=sr);
這里看到的是句子的波形表示。
1、波形 - 信號的時域表示
之前稱它為時間序列數據,但現在我們稱它為波形? 當只看這個音頻文件的一小部分時,這一點變得更加清晰。 下圖顯示了與上面相同的內容,但這次只有 62.5 毫秒。
我們看到的是一個時間信號,它以不同的頻率和幅度在值 0 附近振盪。該信號表示氣壓隨時間的變化,或揚聲器膜(或耳膜)的物理位移 . 這就是為什麼這種對音頻數據的描述也稱為波形的原因。
頻率是該信號振盪的速度。 低頻例如 60 Hz 可能是低音吉他的聲音,而鳥兒的歌聲可能是 8000 Hz 的更高頻率。 我們人類語言通常介於兩者之間。
要知道這個信號在單位時間內從連續信號中提取並組成離散信號的采樣個數,我們使用赫茲(Hz)來表示每秒的采樣個數。 16'000 或 16k Hz表示美標採集了16000次。 我們在上圖中可以看到的 1'000 個時間點代表了 62.5 毫秒(1000/16000 = 0.0625)的音頻信號。
2、傅里葉變換——信號的頻域表示
雖然之前的可視化可以告訴我們什麼時候發生了(即 2 秒左右似乎有很多波形信號),但它不能真正告訴我們它發生的頻率。 因為波形向我們顯示了有關時間的信息,所以該信號也被稱為信號的時域表示。
可以使用快速傅立葉變換,反轉這個問題並獲得關於存在哪些頻率的信息,同時丟棄掉關於時間的信息。 在這種情況下,信號表示被稱為信號的頻域表示。
讓我們看看之前的句子在頻域中的表現。
import scipy
import numpy as np
# Applies fast fourier transformation to the signal and takes absolute values
y_freq = np.abs(scipy.fftpack.fft(y))
# Establishes all possible frequency
# (dependent on the sampling rate and the length of the signal)
f = np.linspace(0, sr, len(y_freq))
# Plot audio signal as frequency information.
plt.figure(figsize=(12, 3))
plt.semilogx(f[: len(f) // 2], y_freq[: len(f) // 2])
plt.xlabel("Frequency (Hz)")
plt.show();
可以在此處看到大部分信號在 ~100 到 ~1000 Hz 之間(即 10² 到 10³ 之間)。 另外,似乎還有一些從 1'000 到 10'000 Hz 的內容。
3、頻譜圖
我們並不總是需要決定時域或頻域。 使用頻譜圖同時表示這兩個領域中的信息,同時將它們的大部差別保持在最低限度。 有多種方法可以創建頻譜圖,但在本文中將介紹常見的三種。
3a 短時傅里葉變換 (STFT)
這時是之前的快速傅立葉變換的小型改編版本,即短時傅立葉變換 (STFT), 這種方式是以滑動窗口的方式計算多個小時間窗口(因此稱為「短時傅立葉」)的 FFT。
import librosa.display
# Compute short-time Fourier Transform
x_stft = np.abs(librosa.stft(y))
# Apply logarithmic dB-scale to spectrogram and set maximum to 0 dB
x_stft = librosa.amplitude_to_db(x_stft, ref=np.max)
# Plot STFT spectrogram
plt.figure(figsize=(12, 4))
librosa.display.specshow(x_stft, sr=sr, x_axis="time", y_axis="log")
plt.colorbar(format="%+2.0f dB")
plt.show();
與所有頻譜圖一樣,顏色代表在給定時間點給定頻率的量(響度/音量)。 +0dB 是最響亮的,-80dB 接近靜音。 在水平 x 軸上我們可以看到時間,而在垂直 y 軸上我們可以看到不同的頻率。
3b 梅爾譜圖
作為 STFT 的替代方案,還可以計算基於 mel 標度的梅爾頻譜圖。 這個尺度解釋了我們人類感知聲音音高的方式。 計算 mel 標度,以便人類將由 mel 標度中的 delta 隔開的兩對頻率感知為具有相同的感知差異。
梅爾譜圖的計算與 STFT 非常相似,主要區別在於 y 軸使用不同的刻度。
# Compute the mel spectrogram
x_mel = librosa.feature.melspectrogram(y=y, sr=sr)
# Apply logarithmic dB-scale to spectrogram and set maximum to 0 dB
x_mel = librosa.power_to_db(x_mel, ref=np.max)
# Plot mel spectrogram
plt.figure(figsize=(12, 4))
librosa.display.specshow(x_mel, sr=sr, x_axis="time", y_axis="mel")
plt.colorbar(format="%+2.0f dB")
plt.show();
與 STFT 的區別可能不太明顯,但如果仔細觀察,就會發現在 STFT 圖中,從 0 到 512 Hz 的頻率在 y 軸上佔用的空間比在 mel 圖中要大得多 .
3c 梅爾頻率倒譜系數 (MFCC)
梅爾頻率倒譜系數 (MFCC) 是上面梅爾頻譜圖的替代表示。 MFCC 相對於 梅爾譜圖的優勢在於特徵數量相當少(即獨特的水平線標度),通常約為 20。
由於梅爾頻譜圖更接近我們人類感知音高的方式,並且 MFCC 只有少數幾個分量特徵,所以大多數機器學習從業者更喜歡 使用MFCC 以「圖像方式」表示音頻數據。 但是對於某些問題,STFT、mel 或波形表示可能會更好。
讓我們繼續計算 MFCC 並繪制它們。
# Extract 'n_mfcc' numbers of MFCCs components (here 20)
x_mfccs = librosa.feature.mfcc(y, sr=sr, n_mfcc=20)
# Plot MFCCs
plt.figure(figsize=(12, 4))
librosa.display.specshow(x_mfccs, sr=sr, x_axis="time")
plt.colorbar()
plt.show();
數據清洗
現在我們更好地理解了音頻數據的樣子,讓我們可視化更多示例。
在這四個示例中,我們可以收集到有關此音頻數據集的更多問題:
· 大多數錄音在錄音的開頭和結尾都有一段較長的靜默期(示例 1 和示例 2)。 這是我們在「修剪」時應該注意的事情。
· 在某些情況下,由於按下和釋放錄制按鈕,這些靜音期會被「點擊」中斷(參見示例 2)。
· 一些錄音沒有這樣的靜音階段,即一條直線(示例 3 和 4)。
· 在收聽這些錄音時,有大量背景噪音。
為了更好地理解這在頻域中是如何表示的,讓我們看一下相應的 STFT 頻譜圖。
當聽錄音時,可以觀察到樣本 3 具有覆蓋多個頻率的不同背景雜訊,而樣本 4 中的背景雜訊相當恆定。 這也是我們在上圖中看到的。 樣本 3 在整個過程中都非常嘈雜,而樣本 4 僅在幾個頻率上(即粗水平線)有雜訊。 我們不會詳細討論如何消除這種噪音,因為這超出了本文的范圍。
但是讓我們研究一下如何消除此類噪音並修剪音頻樣本的「捷徑」。 雖然使用自定義過濾函數的更手動的方法可能是從音頻數據中去除雜訊的最佳方法,但在我們的例子中,將推薦使用實用的 python 包 noiserece。
import noiserece as nr
from scipy.io import wavfile
# Loop through all four samples
for i in range(4):
# Load audio file
fname = "c4_sample-%d.mp3" % (i + 1)
y, sr = librosa.load(fname, sr=16_000)
# Remove noise from audio sample
reced_noise = nr.rece_noise(y=y, sr=sr, stationary=False)
# Save output in a wav file as mp3 cannot be saved to directly
wavfile.write(fname.replace(".mp3", ".wav"), sr, reced_noise)
聆聽創建的 wav 文件,可以聽到噪音幾乎完全消失了。 雖然我們還引入了更多的代碼,但總的來說我們的去噪方法利大於弊。
對於修剪步驟,可以使用 librosa 的 .effects.trim() 函數。每個數據集可能需要一個不同的 top_db 參數來進行修剪,所以最好進行測試,看看哪個參數值好用。 在這個的例子中,它是 top_db=20。
# Loop through all four samples
for i in range(4):
# Load audio file
fname = "c4_sample-%d.wav" % (i + 1)
y, sr = librosa.load(fname, sr=16_000)
# Trim signal
y_trim, _ = librosa.effects.trim(y, top_db=20)
# Overwrite previous wav file
wavfile.write(fname.replace(".mp3", ".wav"), sr, y_trim)
現在讓我們再看一下清理後的數據。
看樣子好多了
特徵提取
數據是干凈的,應該繼續研究可以提取的特定於音頻的特徵了。
1、開始檢測
通過觀察一個信號的波形,librosa可以很好地識別一個新口語單詞的開始。
# Extract onset timestamps of words
onsets = librosa.onset.onset_detect(
y=y, sr=sr, units="time", hop_length=128, backtrack=False)
# Plot onsets together with waveform plot
plt.figure(figsize=(8, 3))
librosa.display.waveplot(y, sr=sr, alpha=0.2, x_axis="time")
for o in onsets:
plt.vlines(o, -0.5, 0.5, colors="r")
plt.show()
# Return number of onsets
number_of_words = len(onsets)
print(f"{number_of_words} onsets were detected in this audio signal.")
>>> 7 onsets were detected in this audio signal
2、錄音的長度
與此密切相關的是錄音的長度。錄音越長,能說的單詞就越多。所以計算一下錄音的長度和單詞被說出的速度。
ration = len(y) / sr
words_per_second = number_of_words / ration
print(f"""The audio signal is {ration:.2f} seconds long,
with an average of {words_per_second:.2f} words per seconds.""")
>>> The audio signal is 1.70 seconds long,
>>> with an average of 4.13 words per seconds.
3、節奏
語言是一種非常悅耳的信號,每個人都有自己獨特的說話方式和語速。因此,可以提取的另一個特徵是說話的節奏,即在音頻信號中可以檢測到的節拍數。
# Computes the tempo of a audio recording
tempo = librosa.beat.tempo(y, sr, start_bpm=10)[0]
print(f"The audio signal has a speed of {tempo:.2f} bpm.")
>>> The audio signal has a speed of 42.61 bpm.
4、基頻
基頻是周期聲音出現時的最低頻率。在音樂中也被稱為音高。在之前看到的譜圖圖中,基頻(也稱為f0)是圖像中最低的亮水平條帶。而在這個基本音之上的帶狀圖案的重復稱為諧波。
為了更好地說明確切意思,下面提取基頻,並在譜圖中畫出它們。
# Extract fundamental frequency using a probabilistic approach
f0, _, _ = librosa.pyin(y, sr=sr, fmin=10, fmax=8000, frame_length=1024)
# Establish timepoint of f0 signal
timepoints = np.linspace(0, ration, num=len(f0), endpoint=False)
# Plot fundamental frequency in spectrogram plot
plt.figure(figsize=(8, 3))
x_stft = np.abs(librosa.stft(y))
x_stft = librosa.amplitude_to_db(x_stft, ref=np.max)
librosa.display.specshow(x_stft, sr=sr, x_axis="time", y_axis="log")
plt.plot(timepoints, f0, color="cyan", linewidth=4)
plt.show();
在 100 Hz 附近看到的綠線是基本頻率。 但是如何將其用於特徵工程呢? 可以做的是計算這個 f0 的具體特徵。
# Computes mean, median, 5%- and 95%-percentile value of fundamental frequency
f0_values = [
np.nanmean(f0),
np.nanmedian(f0),
np.nanstd(f0),
np.nanpercentile(f0, 5),
np.nanpercentile(f0, 95),
]
print("""This audio signal has a mean of {:.2f}, a median of {:.2f}, a
std of {:.2f}, a 5-percentile at {:.2f} and a 95-percentile at {:.2f}.""".format(*f0_values))
>>> This audio signal has a mean of 81.98, a median of 80.46, a
>>> std of 4.42, a 5-percentile at 76.57 and a 95-percentile at 90.64.
除以上說的技術意外,還有更多可以探索的音頻特徵提取技術,這里就不詳細說明了。
音頻數據集的探索性數據分析 (EDA)
現在我們知道了音頻數據是什麼樣子以及如何處理它,讓我們對它進行適當的 EDA。 首先下載一個數據集Kaggle 的 Common Voice 。 這個 14 GB 的大數據集只是來自 Mozilla 的 +70 GB 大數據集的一個小的快照。 對於本文這里的示例,將只使用這個數據集的大約 9'000 個音頻文件的子樣本。
看看這個數據集和一些已經提取的特徵。
1、特徵分布調查
目標類別年齡和性別的類別分布。
目標類別分布是不平衡的
下一步,讓我們仔細看看提取的特徵的值分布。
除了 words_per_second,這些特徵分布中的大多數都是右偏的,因此可以從對數轉換中獲益。
import numpy as np
# Applies log1p on features that are not age, gender, filename or words_per_second
df = df.apply(
lambda x: np.log1p(x)
if x.name not in ["age", "gender", "filename", "words_per_second"]
else x)
# Let's look at the distribution once more
df.drop(columns=["age", "gender", "filename"]).hist(
bins=100, figsize=(14, 10))
plt.show();
好多了,但有趣的是 f0 特徵似乎都具有雙峰分布。 讓我們繪制與以前相同的內容,但這次按性別分開。
正如懷疑的那樣,這里似乎存在性別效應! 但也可以看到,一些 f0 分數(這里特別是男性)比應有的低和高得多。 由於特徵提取不良,這些可能是異常值。 仔細看看下圖的所有數據點。
# Plot sample points for each feature indivially
df.plot(lw=0, marker=".", subplots=True, layout=(-1, 3),
figsize=(15, 7.5), markersize=2)
plt.tight_layout()
plt.show();
鑒於特徵的數量很少,而且有相當漂亮的帶有明顯尾部的分布,可以遍歷它們中的每一個,並逐個特徵地確定異常值截止閾值。
2、特徵的相關性
下一步,看看所有特徵之間的相關性。 但在這樣做之前需要對非數字目標特徵進行編碼。 可以使用 scikit-learn 的 OrdinalEncoder 來執行此操作,但這可能會破壞年齡特徵中的正確順序。 因此在這裏手動進行映射。
# Map age to appropriate numerical value
df.loc[:, "age"] = df["age"].map({
"teens": 0,
"twenties": 1,
"thirties": 2,
"fourties": 3,
"fifties": 4,
"sixties": 5})
# Map gender to corresponding numerical value
df.loc[:, "gender"] = df["gender"].map({"male": 0, "female": 1})
現在可以使用 pandas 的 .corr() 函數和 seaborn 的 heatmap() 來更深入地了解特徵相關性。
import seaborn as sns
plt.figure(figsize=(8, 8))
df_corr = df.corr() * 100
sns.heatmap(df_corr, square=True, annot=True, fmt=".0f",
mask=np.eye(len(df_corr)), center=0)
plt.show();
非常有趣!提取的 f0 特徵似乎與性別目標有相當強的關系,而年齡似乎與任何其他的特徵都沒有太大的相關性。
3、頻譜圖特徵
目前還沒有查看實際錄音。 正如之前看到的,有很多選擇(即波形或 STFT、mel 或 mfccs 頻譜圖)。
音頻樣本的長度都不同,這意味著頻譜圖也會有不同的長度。 因此為了標准化所有錄音,首先要將它們剪切到正好 3 秒的長度:太短的樣本會被填充,而太長的樣本會被剪掉。
一旦計算了所有這些頻譜圖,我們就可以繼續對它們執行一些 EDA! 而且因為看到「性別」似乎與錄音有特殊的關系,所以分別可視化兩種性別的平均梅爾譜圖,以及它們的差異。
男性說話者的平均聲音低於女性。 這可以通過差異圖中的較低頻率(在紅色水平區域中看到)的更多強度來看出。
模型選擇
現在已經可以進行建模了。我們有多種選擇。關於模型,我們可以……
· 訓練我們經典(即淺層)機器學習模型,例如 LogisticRegression 或 SVC。
· 訓練深度學習模型,即深度神經網路。
· 使用 TensorflowHub 的預訓練神經網路進行特徵提取,然後在這些高級特徵上訓練淺層或深層模型
而我們訓練的數據是
· CSV 文件中的數據,將其與頻譜圖中的「mel 強度」特徵相結合,並將數據視為表格數據集
· 單獨的梅爾譜圖並將它們視為圖像數據集
· 使用TensorflowHub現有模型提取的高級特徵,將它們與其他表格數據結合起來,並將其視為表格數據集
當然,有許多不同的方法和其他方法可以為建模部分創建數據集。因為我們沒有使用全量的數據,所以在本文我們使用最簡單的機器學習模型。
經典(即淺層)機器學習模型
這里使用EDA獲取數據,與一個簡單的 LogisticRegression 模型結合起來,看看我們能在多大程度上預測說話者的年齡。除此以外還使用 GridSearchCV 來探索不同的超參數組合,以及執行交叉驗證。
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import RobustScaler, PowerTransformer, QuantileTransformer
from sklearn.decomposition import PCA
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
# Create pipeline
pipe = Pipeline(
[
("scaler", RobustScaler()),
("pca", PCA()),
("logreg", LogisticRegression(class_weight="balanced")),
]
)
# Create grid
grid = {
"scaler": [RobustScaler(), PowerTransformer(), QuantileTransformer()],
"pca": [None, PCA(0.99)],
"logreg__C": np.logspace(-3, 2, num=16),
}
# Create GridSearchCV
grid_cv = GridSearchCV(pipe, grid, cv=4, return_train_score=True, verbose=1)
# Train GridSearchCV
model = grid_cv.fit(x_tr, y_tr)
# Collect results in a DataFrame
cv_results = pd.DataFrame(grid_cv.cv_results_)
# Select the columns we are interested in
col_of_interest = [
"param_scaler",
"param_pca",
"param_logreg__C",
"mean_test_score",
"mean_train_score",
"std_test_score",
"std_train_score",
]
cv_results = cv_results[col_of_interest]
# Show the dataframe sorted according to our performance metric
cv_results.sort_values("mean_test_score", ascending=False)
作為上述 DataFrame 輸出的補充,還可以將性能得分繪制為探索的超參數的函數。 但是因為使用了有多個縮放器和 PCA ,所以需要為每個單獨的超參數組合創建一個單獨的圖。
在圖中,可以看到總體而言模型的表現同樣出色。 當降低 C 的值時,有些會出現更快的「下降」,而另一些則顯示訓練和測試(這里實際上是驗證)分數之間的差距更大,尤其是當我們不使用 PCA 時。
下面使用 best_estimator_ 模型,看看它在保留的測試集上的表現如何。
# Compute score of the best model on the withheld test set
best_clf = model.best_estimator_
best_clf.score(x_te, y_te)
>>> 0.4354094579008074
這已經是一個很好的成績了。 但是為了更好地理解分類模型的表現如何,可以列印相應的混淆矩陣。
雖然該模型能夠檢測到比其他模型更多的 20 歲樣本(左混淆矩陣),但總體而言,它實際上在對 10 歲和 60 歲的條目進行分類方面效果更好(例如,准確率分別為 59% 和 55%)。
總結
在這篇文章中,首先看到了音頻數據是什麼樣的,然後可以將其轉換成哪些不同的形式,如何對其進行清理和探索,最後如何將其用於訓練一些機器學習模型。如果您有任何問題,請隨時發表評論。
最後本文的源代碼在這里下載:
https://www.overfit.cn/post/
作者:Michael Notter