Python Audio‑Based Parkinson’s Disease Detection Using Machine Learning
This tutorial demonstrates how to build a Python library that extracts acoustic measurements from healthy and Parkinson’s disease audio recordings, constructs a machine‑learning dataset, trains a logistic‑regression classifier with scikit‑learn, evaluates its accuracy, and provides functions to load and use the trained model in other applications.
We create a simple Python machine‑learning algorithm to diagnose whether a person is a Parkinson’s patient based on voice recordings. A collection of audio files from healthy subjects and Parkinson’s patients is used to build the dataset by measuring various acoustic features.
First, we import the required libraries:
<code>import glob
import numpy as np
import pandas as pd
import parselmouth
from parselmouth.praat import call</code>A function measurePitch is defined to compute several measurements (jitter, shimmer, harmonicity, etc.) using the parselmouth library, which provides a Python interface to Praat.
<code>def measurePitch(voiceID, f0min, f0max, unit):
sound = parselmouth.Sound(voiceID) # read the sound
pitch = call(sound, "To Pitch", 0.0, f0min, f0max)
pointProcess = call(sound, "To PointProcess (periodic, cc)", f0min, f0max)
localJitter = call(pointProcess, "Get jitter (local)", 0, 0, 0.0001, 0.02, 1.3)
...
return localJitter, localabsoluteJitter, rapJitter, ppq5Jitter, localShimmer, localdbShimmer, apq3Shimmer, aqpq5Shimmer, apq11Shimmer, hnr05, hnr15, hnr25, hnr35, hnr38</code>Lists are created for each measurement and for the label indicating Parkinson’s (1) or healthy (0). Four for loops iterate over the audio files in the four directories (PD/SpontaneousDialogue, PD/ReadText, HC/SpontaneousDialogue, HC/ReadText), calling measurePitch and appending the results to the corresponding lists.
<code>for wave_file in glob.glob("audio/SpontaneousDialogue/PD/*.wav"):
sound = parselmouth.Sound(wave_file)
(localJitter, localabsoluteJitter, rapJitter, ppq5Jitter, localShimmer, localdbShimmer, apq3Shimmer, aqpq5Shimmer, apq11Shimmer, hnr05, hnr15, hnr25, hnr35, hnr38) = measurePitch(sound, 75, 1000, "Hertz")
...
parkinson_list.append(1)
</code>After populating the lists, they are combined into a pandas DataFrame, forming the final dataset which is saved to processed_results.csv . Missing values are filled with column means.
<code>pred = pd.DataFrame(np.column_stack([parkinson_list, localJitter_list, ... , hnr25_list]),
columns=["Parkinson","Jitter_rel","Jitter_abs","Jitter_RAP","Jitter_PPQ","Shim_loc","Shim_dB","Shim_APQ3","Shim_APQ5","Shi_APQ11","hnr05","hnr15","hnr25"])
pred["hnr25"].fillna(parkinson["hnr25"].mean(), inplace=True)
pred["hnr15"].fillna(parkinson["hnr15"].mean(), inplace=True)
pred.to_csv("processed_results.csv", index=False)
</code>The dataset is then used to train a logistic‑regression model with scikit‑learn. After splitting into training and test sets, the model is fitted and its accuracy is printed (≈0.63 on the test set).
<code>from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(parkinson[predictors], parkinson['Parkinson'], test_size=0.25, random_state=1)
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
test_score = clf.score(X_test, y_test)
print('train accuracy =', train_score)
print('test accuracy =', test_score)
</code>The trained model is saved with joblib so it can be loaded by other programs.
<code>import joblib
clf.fit(X_train, y_train)
joblib.dump(clf, "trainedModel.sav")
</code>A reusable Python library is provided, containing loadModel , the same measurePitch function, and a predict function that takes a wav file path, extracts features, builds a one‑row DataFrame, and returns True if the model predicts Parkinson’s disease.
<code>def loadModel(PATH):
clf = joblib.load(PATH)
return clf
def predict(clf, wavPath):
...
resp = clf.predict(toPred)
return resp == "[1.]"
</code>Example usage of the library:
<code>from RecognitionLib import *
path = "../trainedModel.sav"
clf = loadModel(path)
print(predict(clf, "../../audio/ok.wav"))
</code>The article notes that increasing the size of the audio dataset (more Parkinson’s samples) would improve model accuracy.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.