Python, daha pratik bir csv oluşturma yöntemi

Herkese merhaba.

  • Kısaca amaçtan bahsedeyim. Path ve Os aracılığıyla “Genres” değişkenine atanmış klasörlerin içerisindeki .wav dosyalarının özelliklerini Librosa ile alıp csv. dosyasına yazdıracağım. Kodun tamamı en alttadır.

Elimde şöyle bir kod var. Günlerdir anlamaya çalışıyorum. Çoğu kısmını anladım fakat bazı yerleri bana zorlama geldi.

  • Anlamadığım bir kısım burası;
header = 'filename chroma_stft rmse spectral_centroid spectral_bandwidth rolloff zero_crossing_rate'
for i in range(1, 21):
    header += f' mfcc{i}'
header += ' label'
header = header.split()

Yukarıda neden range(1, 21) kadar mfcc içerisinde header içeriği oluşturmuş.

        for e in mfcc:
            to_append += f' {np.mean(e)}'
        to_append += f' {g}'

Bu şekilde listeye atayarak yazdırmak yerine Pandas ile spesifik bir şekilde sütun ve satırlar oluşturup daha kısa ve işlevsel bir biçimde kod yazılabilir sanırım. Ama okuduğum kaynaklar varolan bir csv dosyasında metod ve fonksiyonların pratiğini yaptırıyor. Bunu nasıl yapacağımı bir türlü çözemedim.

Daha kullanışlı ve pratik bir yol varsa söyleyebilir misiniz?

Kodun tamamı;

import librosa
import pandas as pd
import numpy as np
import pathlib
import os
import csv

header = 'filename chroma_stft rmse spectral_centroid spectral_bandwidth rolloff zero_crossing_rate'
for i in range(1, 21):
    header += f' mfcc{i}'
header += ' label'
header = header.split()

file = open('dataset.csv', 'w', newline='')
with file:
    writer = csv.writer(file)
    writer.writerow(header)
genres = 'blues classical country disco hiphop jazz metal pop reggae rock'.split()
for g in genres:
    for filename in os.listdir(f'./drive/My Drive/genres/{g}'):
        songname = f'./drive/My Drive/genres/{g}/{filename}'
        y, sr = librosa.load(songname, mono=True, duration=30)
        rmse = librosa.feature.rmse(y=y)
        chroma_stft = librosa.feature.chroma_stft(y=y, sr=sr)
        spec_cent = librosa.feature.spectral_centroid(y=y, sr=sr)
        spec_bw = librosa.feature.spectral_bandwidth(y=y, sr=sr)
        rolloff = librosa.feature.spectral_rolloff(y=y, sr=sr)
        zcr = librosa.feature.zero_crossing_rate(y)
        mfcc = librosa.feature.mfcc(y=y, sr=sr)
        to_append = f'{filename} {np.mean(chroma_stft)} {np.mean(rmse)} {np.mean(spec_cent)} {np.mean(spec_bw)} {np.mean(rolloff)} {np.mean(zcr)}'    
        for e in mfcc:
            to_append += f' {np.mean(e)}'
        to_append += f' {g}'
        file = open('dataset.csv', 'a', newline='')
        with file:
            writer = csv.writer(file)
            writer.writerow(to_append.split())

Bunu örneklemek için şöyle birşey de yazabilirsiniz. Değişkene atadığımız bir dizin var. O dizin içerisinde bulunan 3 tane ses dosyasının boyutunu bir csv dosyasına yazdırsın.
Bunu yazarken Pandas ile faydalanırsak sorumun cevabı olmuş olacak.

Burasi header isimli, belirli bir degere sahip bir string degisken olusturuyor. header = "deger" koduna esdeger.

:person_shrugging:

range(1, 21) kadar mfcc datasi var diye olabilir mi?

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_csv.html#pandas-dataframe-to-csv

Hangi kaynaklar?

csv modulu olabilir.

Siz niye yapmiyorsunuz?
Kaynagi belli olmayan bir kodun nasil calistigini anlamaya calismaktan daha faydali olacaktir.
Problemi uce ayirmamiz lazim:

  1. Dizindeki ses dosyalarini bulma.
  2. Bir ses dosyasinin boyutunu ogrenme.
  3. Ses dosyasi boyutuna benzer bir sayiyi CSV dosyasina yazdirma.

Bunlarin ucunun de birbirinden bagimsiz olmasi lazim, yoksa belirli bir sirayla ilerlemek gerekir.

Mesela yukaridaki kodda bagimsiz degiller ve yazdigim sirada ilerlememiz lazim. Elimizde ses dosyalari olmadigi icin kodu calistiramiyoruz. bkz: Soru Sorarken Sıkça Düşülen Hatalar #7

CSV yazmak icinse ve veriler hali hazirda Pandas formatinda degilse csv modulu daha iyi olacaktir.

Teşekkür ederim.

Kodun kaynağı burası:

import glob
path = ‘C:\Users\Furkan\Desktop\Klasör1’

wav = glob.glob(‘C:\Users\Furkan\Desktop\Klasör\*wav’)
wav1 = []
for w in wav:
wav1.append(w[31:])
print(wav1)
Çıktısı:
[‘blues.00000.wav’,
‘blues.00001.wav’,
‘blues.00002.wav’,
‘blues.00003.wav’,
‘blues.00004.wav’]

Tamam. Dosyaların isimlerini aldım, listeye atadım, ama şunun içerisine;

librosa.feature.rms(wav1)

Liste yollarsam normal olarak hata verir. Listedeki her elemanı yollamamın yolu index değerleriyle göndermek. İşte burada tıkanıyorum. Listedeki her elemanı tek tek yukarıdaki fonksiyona nasıl sokabilirim.

Bu dökümanları tekrar okuyacağım.
https://docs.python.org/3/library/csv.html
https://docs.python.org/3/library/glob.html

https://towardsdatascience.com/a-complete-pandas-guide-2dc53c77a002

Bu ses dosyalarının ve kütüphanelerin sizde mevcut olduğunu düşündüğümü düşünmemişsinizdir umarım :no_mouth:

for loop’u kullanarak. (bkz: Döngüler (Loops) — Yazbel Python Belgeleri)

xs = ['a.wav', 'b.wav']
for x in xs:
    ...

for i, x in enumerate(xs):
    ...

for i in range(len(xs)):
    x = xs[i]
    ...

Yok, buradaki yanlis dusunce dosyalarin baskasinda olmasi degil, baskasinin dosyalar olmadan kodu kullanabilmesi :slight_smile:

En azindan dedigim sekilde fonksiyonlara ayrilmasi lazim. Elzem degil, ama belirteyim dedim.

Kodu parçalara ayırdım ve tekrardan inceledim. Düşündüğüm kadar karmaşık olmadığını gördüm. Bu temel ve önemli bir işlem. Bir klasörün içerisindeki öğrelere erişip onları işleme koymak her zaman karşılaşacağım bir senaryo ve bu işlemde yetersiz olmak beni huzursuz etti. Ama sonunda mantığını anladım. Bu gece biraz daha pratik yaparsam gönül rahatlığıyla uyuyabilirim :smiling_face:

Tekrardan yardımınız için teşekkür ederim. İyi çalışmalar.

1 Beğeni

Kodu (veya algoritmayi veya problemi) birbirinden bagimsiz parcalaya ayirabilmek yazilim tasariminin en temel becerisi. Soru sorarken bile eksigi/varligi hissedilebiliyor. Bu yuzden bu son mesajiniz beni sevindirdi.

import csv
import glob

def get_filenames():
    return glob.glob('/tmp/*.png')

def get_audio_length(filename):
    return len(filename) #TODO

def write_csv(filename, rows):
    with open(filename, 'w') as f:
        writer = csv.writer(f)
        writer.writerows(rows)

def main():
    files = get_filenames()

    rows = [["Filename", "Audio Length"]]
    for f in files:
        audio_length = get_audio_length(f)
        row = [f, audio_length]
        rows.append(row)

    write_csv('/tmp/files.csv', rows)

if __name__ == '__main__':
    main()
Filename,Audio Length
/tmp/noise_scale_0.3.png,24
/tmp/noise_scale_0.50.png,25
/tmp/noise_scale_0.55.png,25
/tmp/noise_original.png,23
/tmp/screenshot_20220429_234249.png,35
/tmp/Figure_101.png,19
/tmp/Figure_100.png,19
2 Beğeni