import pandas as pd
import numpy as np
import string
import nltk
from nltk.tokenize import word_tokenize
from wordcloud import WordCloud
from transformers import pipeline
import matplotlib.pyplot as plt
import matplotlib.cm as cm
'fivethirtyeight') plt.style.use(
Giriş
Faiz kararları sadece sayılardan ibaret değildir. Türkiye Cumhuriyet Merkez Bankası’nın (TCMB) faiz oranlarına ilişkin basın duyuruları da büyük bir öneme sahiptir. Bu duyurular, TCMB’nin kararlarını destekleyen veya açıklayan bir metin içerir ve bu metin, ekonomi uzmanları, yatırımcılar ve piyasa analistleri için kritik bir kaynaktır. Basın duyuruları temelde, TCMB’nin ekonomik göstergeleri nasıl yorumladığını ve gelecekteki politika eğilimlerini nasıl değerlendirdiğini içerir.
Veri seti, Erdem Başçı ve Yaşar Fatih Karahan arası dönemlerde yayınlanan 148 adet İngilizce duyuru metnini kapsamaktadır. Son veri 2024 yılının Nisan ayına aittir. cbrt_press_releases
isimli excel dosyasında bulunan veri setine buradan ulaşabilirsiniz.
Kullanılacak Kütüphaneler
Veri Setinin İçe Aktarılması ve Bazı Ayarların Yapılması
= pd.read_excel('cbrt_press_releases.xlsx')
df
'Date'] = pd.to_datetime(df['Date'], dayfirst=True)
df[= df.sort_values(by='Date')
df = df.set_index('Date') df
Metin İçeriğinin Analizi
Metin analizinde NLTK
kütüphanesini kullanacağız. NLTK
(Natural Language Toolkit), doğal dil işleme (NLP) görevlerini gerçekleştirmek için kullanılan bir kütüphanedir.
Aşağıdaki gerekli olan indirme işlemlerini yapalım.
'punkt')
nltk.download('stopwords') nltk.download(
punkt
, cümlelerin ve kelimelerin tokenize (parçalama) edilmesi için kullanılan bir veri modelidir. Tokenization, metni daha küçük parçalara ayırma işlemidir ve doğal dil işleme uygulamalarında sıkça kullanılır.
stopwords
, dilin yapısı gereği sıklıkla karşılaşılan ve genellikle metin analizi veya doğal dil işleme uygulamalarında önemsiz olarak kabul edilen kelimelerdir.
Tarihlere ve başkanlara göre kelime sayıları
Kelimeleri sayacak word_counter
isimli ve text
parametresi bulunan bir fonksiyon yazalım.
def word_counter(text):
= text.translate(str.maketrans('', '', string.punctuation))
text = text.translate(str.maketrans('', '', '\n\xa0'))
text = text.lower()
text = word_tokenize(text)
tokens return len(tokens)
Yukarıda ilk olarak, metindeki noktalama işaretlerini (string.punctuation
ile tanımlı olanlar) kaldırıyoruz. Bu, metindeki noktalama işaretlerinin (virgül, nokta, ünlem işareti vb.) kelime sayısını etkilememesini sağlıyor. Ardından, metindeki boşlukları ve diğer belirli karakterleri (newline karakteri \n
ve non-breaking space karakteri \xa0
) kaldırıyoruz. Bu, metindeki boşlukların kelime sayısını etkilememesini sağlıyor. Metni lower()
ile küçük harfe dönüştürüyoruz. Bu, büyük ve küçük harflerin ayrımını kaldırarak aynı kelimenin farklı biçimlerini aynı olarak değerlendirmesini sağlıyor. Metni word_tokenize()
ile kelime parçalarına ayırıyoruz (tokenize işlemi). Bu, metindeki her bir kelimeyi ayrı bir öğe olarak ele alarak bu öğelerin sayısını saymamızı sağlıyor. Son olarak, kelime listesinin uzunluğunu len()
ile hesaplayarak bu değeri döndürüyoruz.
'Word Count'] = df['Text'].apply(word_counter)
df[
= len(df['Governor'].unique())
num_governors = cm.Set1(np.linspace(0, 1, num_governors))
colors = df['Governor'].unique()
unique_governors
=(12, 7))
plt.figure(figsizefor i, governor in enumerate(unique_governors):
= df[df['Governor'] == governor]
data 'Word Count'], label=governor, linestyle='-', color=colors[i])
plt.plot(data.index, data[
'Word Counts by Dates and Governors')
plt.title(
plt.text(0.99,
-0.1,
"Based on CBRT's press releases on interest rates.",
='bottom',
verticalalignment='right',
horizontalalignment=plt.gca().transAxes,
transform='gray',
color=10,
fontsize='italic'
fontstyle
)True)
plt.grid(='small')
plt.legend(fontsize
plt.tight_layout() plt.show()
Yukarıda ilk olarak, DataFrame’de bulunan Text
sütunundaki her bir metin için word_counter
fonksiyonunu çağırıyoruz ve her bir metnin kelime sayısı hesaplıyoruz. Görselde kullanmak için num_governors
değişkenine başkan sayısını, colors
değişkenine de bu başkan sayısı kadar renk atıyoruz. unique_governors
ise daha sonra başkanları sırasıyla kullanacağımız için oluşturduğumuz bir değişken oluyor. Görseli oluştururken lejanttaki dönemlerine göre başkan sıralamasının önemini koruyoruz.
Başkanlara göre kelime bulutları
= df.groupby('Governor')['Text'].apply(' '.join)
governors_texts
= plt.subplots(7, 1, figsize=(16, 18))
fig, axs for i, governor in enumerate(unique_governors, 1):
= governors_texts[governor]
text = text.translate(str.maketrans('', '', string.punctuation))
text = text.translate(str.maketrans('', '', '\n\xa0'))
text = text.lower()
text = WordCloud(
wordcloud ='white',
background_color='gray',
colormap='black',
contour_color=1
contour_width
).generate(text)
-1].imshow(wordcloud, interpolation='bilinear')
axs[i-1].set_title(f'Word Cloud for Governor {governor}', fontsize=12)
axs[i-1].axis('off')
axs[i
plt.figtext(0.99,
-0.3,
"Based on CBRT's press releases on interest rates.",
='bottom',
verticalalignment='right',
horizontalalignment=plt.gca().transAxes,
transform='gray',
color=9,
fontsize='italic'
fontstyle
)
plt.tight_layout() plt.show()
Yukarıda, governors_texts
ile başkanların kendi dönemlerinde yayınlanan duyuru metinlerini bir araya getiriyoruz. Ardından, WordCloud
nesnesi oluşturarak bir kelime bulutu oluşturma işlemini gerçekleştiriyoruz. Detaylı bakalım.
WordCloud
nesnesini oluştururken aşağıdaki parametreleri ve değerlerini kullandık.
background_color='white'
, kelime bulutunun arka plan rengini beyaz yapıyor. Yani, kelime bulutunun içindeki kelimeler beyaz bir arka plan üzerine yerleştiriliyor. colormap='gray'
, kelime bulutunda kullanılacak renk haritasını gri tonlarda olacak şekilde ayarlıyor. Kelimelerin yoğunluklarına göre farklı gri tonları kullanılıyor. contour_color='black'
, kelime bulutunun kenar çizgilerinin rengini siyah yapıyor. Bu, kelime bulutunu çevreleyen konturun siyah olacağı anlamına gelir. contour_width=1
, kelime bulutunun kenar çizgilerinin kalınlığı 1 piksel olarak ayarlıyor. Bu, konturun ince olacağı anlamına gelir.
interpolation
parametresine atadığımız bilinear
değeri, görüntüyü daha pürüzsüz bir şekilde yeniden örnekleme yaparak görüntülerken, kenarları daha yumuşak hale getiriyor.
Tarihlere göre metinlerdeki pozitif/negatif duygu değişimleri
CentralBankRoBERTa
, bir LLM’dir (large language model veya büyük dil modeli).
CentralBankRoBERTa
, temelde beş temel makroekonomik aktörü ayıran bir ekonomik aktör sınıflandırıcısı ile merkez bankası iletişimlerindeki cümlelerin duygusal içeriğini belirleyen ikili bir duygu sınıflandırıcısını birleştirir. Bu, merkez bankası iletişimlerindeki cümlelerin duygusal tonunu ve ekonomik aktörleri tanımak için kullanılabilir.
Mimarisi aşağıdaki gibidir.
SentimentClassifier
modeli, verilen bir cümlenin hane halkları, işletmeler, finans sektörü veya hükümet için olumlu mu yoksa olumsuz mu olduğunu belirlemek amacıyla tasarlanmıştır. Bu model, RoBERTa mimarisine dayanır ve doğru tahminler sağlamak için çeşitli ve kapsamlı bir veri kümesinde ince ayarlanmıştır (fine-tuned). Bir merkez bankasının iletişimini analiz etmek için duygusal içerikle ilgili uygun bir doğal dil işleme yöntemini test etmek üzere yapılan çalışmada FED, ECB ve BIS’den toplam 13,458 önceden etiketlenmiş cümle örneği kullanılmıştır.
Performans metrikleri şöyledir: Accuracy: 88%, F1 Score: 0.88, Precision: 0.88 ve Recall: 0.88
= pipeline(
sentiment_classifier 'text-classification',
='Moritz-Pfeifer/CentralBankRoBERTa-sentiment-classifier'
model
)
def classify_sentences(text):
= text.replace('\n', '').replace('\xa0', '')
text = text.split('. ')
sentences = [sentence + '.' if not sentence.endswith('.') else sentence for sentence in sentences]
sentences = 0
positive_count = 0
negative_count for sentence in sentences:
= sentiment_classifier(sentence)
sentiment_result += sum(1 for item in sentiment_result if item['label'] == 'positive')
positive_count += sum(1 for item in sentiment_result if item['label'] == 'negative')
negative_count return positive_count, negative_count
Yukarıda ilk olarak, pipeline
fonksiyonunu çağırarak bir duygu sınıflandırma pipeline’ı oluşturuyoruz. Burada kullanılan model, Moritz Pfeifer tarafından oluşturulmuş CentralBankRoBERTa
modelidir. Ardından, classify_sentences()
fonksiyonunu tanımlıyoruz. Bu fonksiyon, bir metin alıyor ve metni cümlelere bölüyor. Metindeki \n
ve \xa0
gibi boşlukları kaldırmak için replace()
kullanıyoruz. Metni bir nokta ve boşluk ile cümlelere bölüyoruz. Cümle nokta ile bitmiyorsa cümlenin sonunda bir nokta olmasını sağlıyoruz. Pozitif ve negatif duyguların sayısını tutmak için positive_count
ve negative_count
isminde iki değişken tanımlıyor ve sıfır değerini atıyoruz. Her cümle için döngü oluşturuyoruz ve sentiment_classifier()
fonksiyonunu çağırarak cümlenin duygusu belirliyoruz. Bu işlem, cümlenin duygusunu tahmin etmek için önceden eğitilmiş modeli kullanıyor. Duygu sonuçlarına bakarak pozitif ve negatif etiket sayılarını hesaplıyoruz. sentiment_result
içindeki her bir öğe için etiketinin positive
veya negative
olup olmadığını kontrol ediyor ve sonuca göre ilgili sayaçları artırıyoruz. Son olarak fonksiyonda toplam pozitif ve negatif etiket sayılarını döndürüyoruz.
Aşağıda ise df
’te, Positive Count
ve Negative Count
sütunları oluşturuyoruz ve classify_sentences()
isimli text
parametreli fonksiyonu çalıştırıyoruz.
'Positive Count'] = 0
df['Negative Count'] = 0
df[
'Positive Count', 'Negative Count']] = df['Text'].apply(classify_sentences).apply(pd.Series)
df[[
=(12, 8))
plt.figure(figsize'Positive Count'], label='Positive Count', color='blue')
plt.plot(df.index, df['Negative Count'], label='Negative Count', color='red')
plt.plot(df.index, df['Positive Count'], df['Negative Count'], color='gray', alpha=0.3)
plt.fill_between(df.index, df['Positive and Negative Sentiment Counts Over Time')
plt.title(
plt.text(0.99,
-0.1,
"Based on CBRT's press releases on interest rates.",
='bottom',
verticalalignment='right',
horizontalalignment=plt.gca().transAxes,
transform='gray',
color=10,
fontsize='italic'
fontstyle
)
plt.legend()
plt.tight_layout() plt.show()
Gelecek içeriklerde görüşmek dileğiyle.