File size: 6,730 Bytes
99d7b92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
import os
import warnings
warnings.filterwarnings('ignore')

class TurkishSentimentAnalyzer:
    def __init__(self):
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        print(f"Using device: {self.device}")
        
        # sentiment model
        model_name = "savasy/bert-base-turkish-sentiment-cased"
        self.tokenizer = AutoTokenizer.from_pretrained(model_name)
        self.model = AutoModelForSequenceClassification.from_pretrained(model_name).to(self.device)
        
        # Lojistik ve satıcı kelimeleri
        self.logistics_seller_words = {
            'kargo', 'kargocu', 'paket', 'paketleme', 'teslimat', 'teslim', 
            'gönderi', 'gönderim', 'ulaştı', 'ulaşım', 'geldi', 'kurye',
            'satıcı', 'mağaza', 'sipariş', 'trendyol', 'tedarik', 'stok',
            'fiyat', 'ücret', 'para', 'bedava', 'indirim', 'kampanya',
            'havale', 'ödeme', 'garanti', 'fatura'
        }

    def predict_sentiment(self, text):
        """Tek bir metin için sentiment tahmini yap"""
        if not isinstance(text, str) or len(text.strip()) == 0:
            return {"label": "Nötr", "score": 0.5}
        
        try:
            inputs = self.tokenizer(text, return_tensors="pt", truncation=True, 
                                  max_length=512, padding=True).to(self.device)
            
            with torch.no_grad():
                outputs = self.model(**inputs)
                probs = torch.nn.functional.softmax(outputs.logits, dim=1)
                prediction = probs.cpu().numpy()[0]

            # İki sınıflı model için (positive/negative)
            score = float(prediction[1])  # Pozitif sınıfın olasılığı
            
            # Daha hassas skor eşikleri
            if score > 0.75:  # Yüksek güvenle pozitif
                label = "Pozitif"
            elif score < 0.25:  # Yüksek güvenle negatif
                label = "Negatif"
            elif score > 0.55:  # Hafif pozitif eğilim
                label = "Pozitif"
            elif score < 0.45:  # Hafif negatif eğilim
                label = "Negatif"
            else:
                label = "Nötr"
                
            return {"label": label, "score": score}
            
        except Exception as e:
            print(f"Error in sentiment prediction: {e}")
            return {"label": "Nötr", "score": 0.5}

    def filter_product_reviews(self, df):
        """Ürün ile ilgili olmayan yorumları filtrele"""
        def is_product_review(text):
            if not isinstance(text, str):
                return False
            return not any(word in text.lower() for word in self.logistics_seller_words)

        filtered_df = df[df['Yorum'].apply(is_product_review)].copy()
        
        print(f"\nFiltreleme İstatistikleri:")
        print(f"Toplam yorum sayısı: {len(df)}")
        print(f"Ürün yorumu sayısı: {len(filtered_df)}")
        print(f"Filtrelenen yorum sayısı: {len(df) - len(filtered_df)}")
        print(f"Filtreleme oranı: {((len(df) - len(filtered_df)) / len(df) * 100):.2f}%")
        
        return filtered_df

    def analyze_reviews(self, df):
        """Tüm yorumları analiz et"""
        print("\nSentiment analizi başlatılıyor...")
        
        filtered_df = self.filter_product_reviews(df)
        
        # Sentiment analizi
        results = []
        for text in filtered_df['Yorum']:
            sentiment = self.predict_sentiment(text)
            results.append(sentiment)
        
        filtered_df['sentiment_score'] = [r['score'] for r in results]
        filtered_df['sentiment_label'] = [r['label'] for r in results]
        
        return filtered_df

    def create_visualizations(self, df):
        """Analiz sonuçlarını görselleştir"""
        if not os.path.exists('images'):
            os.makedirs('images')
        
        # 1. Sentiment Dağılımı
        plt.figure(figsize=(12, 6))
        sns.countplot(data=df, x='sentiment_label', 
                     order=['Pozitif', 'Nötr', 'Negatif'])
        plt.title('Sentiment Dağılımı')
        plt.tight_layout()
        plt.savefig('images/sentiment_distribution.png', bbox_inches='tight', dpi=300)
        plt.close()

        # 2. Yıldız-Sentiment İlişkisi
        plt.figure(figsize=(12, 6))
        df_mean = df.groupby('Yıldız Sayısı')['sentiment_score'].mean().reset_index()
        sns.barplot(data=df_mean, x='Yıldız Sayısı', y='sentiment_score')
        plt.title('Yıldız Sayısına Göre Ortalama Sentiment Skoru')
        plt.tight_layout()
        plt.savefig('images/star_sentiment_relation.png', bbox_inches='tight', dpi=300)
        plt.close()

        # 3. Sentiment Score Dağılımı
        plt.figure(figsize=(12, 6))
        sns.histplot(data=df, x='sentiment_score', bins=30)
        plt.title('Sentiment Score Dağılımı')
        plt.tight_layout()
        plt.savefig('images/sentiment_score_distribution.png', bbox_inches='tight', dpi=300)
        plt.close()

    def print_statistics(self, df):
        """Analiz istatistiklerini yazdır"""
        print("\nSentiment Analizi Sonuçları:")
        print("-" * 50)
        
        sentiment_counts = df['sentiment_label'].value_counts()
        total_reviews = len(df)
        
        for label, count in sentiment_counts.items():
            percentage = (count / total_reviews) * 100
            print(f"{label}: {count} yorum ({percentage:.2f}%)")
        
        print("\nYıldız Bazlı Sentiment Skorları:")
        print("-" * 50)
        star_means = df.groupby('Yıldız Sayısı')['sentiment_score'].mean()
        for star, score in star_means.items():
            print(f"{star} Yıldız ortalama sentiment skoru: {score:.3f}")

def main():
    df = pd.read_csv('data/macbook_product_comments_with_ratings.csv')
    
    analyzer = TurkishSentimentAnalyzer()
    
    print("Analiz başlatılıyor...")
    analyzed_df = analyzer.analyze_reviews(df)
    
    print("\nGörselleştirmeler oluşturuluyor...")
    analyzer.create_visualizations(analyzed_df)
    
    analyzer.print_statistics(analyzed_df)
    
    output_file = 'sentiment_analyzed_reviews.csv'
    analyzed_df.to_csv(output_file, index=False, encoding='utf-8-sig')
    print(f"\nSonuçlar '{output_file}' dosyasına kaydedildi.")

if __name__ == "__main__":
    main()