-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathanalyse_dataset.py
More file actions
474 lines (391 loc) · 20.4 KB
/
Copy pathanalyse_dataset.py
File metadata and controls
474 lines (391 loc) · 20.4 KB
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
#!/usr/bin/env python3
"""
Comprehensive VoicePersona Dataset Analysis
Generates extensive visualizations and statistics
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from pathlib import Path
import json
from datasets import load_from_disk
from collections import Counter
import warnings
warnings.filterwarnings('ignore')
# Set style
plt.style.use('default')
sns.set_palette("husl")
class VoicePersonaAnalyzer:
def __init__(self, dataset_path="voicepersona_combined"):
self.dataset_path = dataset_path
self.output_dir = Path("analyse")
self.output_dir.mkdir(exist_ok=True)
# Load dataset
print("Loading dataset...")
if Path(dataset_path).exists():
self.dataset = load_from_disk(dataset_path)
self.df = self.dataset.to_pandas()
else:
print(f"Dataset not found at {dataset_path}")
return
print(f"Loaded {len(self.df)} samples")
def basic_statistics(self):
"""Generate basic dataset statistics"""
print("\n📊 BASIC STATISTICS")
print("=" * 50)
stats = {
'total_samples': len(self.df),
'unique_speakers': self.df['speaker_id'].nunique(),
'total_duration_hours': self.df['duration'].sum() / 3600,
'avg_duration_seconds': self.df['duration'].mean(),
'datasets': self.df['dataset'].value_counts().to_dict(),
'genders': self.df['gender'].value_counts().to_dict(),
'age_groups': self.df['age'].value_counts().to_dict(),
'unique_accents': self.df['accent'].nunique(),
'top_accents': self.df['accent'].value_counts().head(10).to_dict()
}
# Save statistics
with open(self.output_dir / "statistics.json", 'w') as f:
json.dump(stats, f, indent=2, default=str)
# Print key stats
print(f"Total Samples: {stats['total_samples']:,}")
print(f"Unique Speakers: {stats['unique_speakers']:,}")
print(f"Total Duration: {stats['total_duration_hours']:.1f} hours")
print(f"Average Duration: {stats['avg_duration_seconds']:.1f} seconds")
print(f"Unique Accents: {stats['unique_accents']}")
return stats
def plot_duration_analysis(self):
"""Audio duration analysis"""
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('Audio Duration Analysis', fontsize=16, fontweight='bold')
# Duration histogram
axes[0,0].hist(self.df['duration'], bins=50, alpha=0.7, color='skyblue', edgecolor='black')
axes[0,0].set_title('Duration Distribution')
axes[0,0].set_xlabel('Duration (seconds)')
axes[0,0].set_ylabel('Frequency')
axes[0,0].axvline(self.df['duration'].mean(), color='red', linestyle='--',
label=f'Mean: {self.df["duration"].mean():.1f}s')
axes[0,0].legend()
# Duration by dataset
sns.boxplot(data=self.df, x='dataset', y='duration', ax=axes[0,1])
axes[0,1].set_title('Duration by Dataset')
axes[0,1].tick_params(axis='x', rotation=45)
# Cumulative duration
sorted_durations = np.sort(self.df['duration'])
cumulative = np.cumsum(sorted_durations) / 3600 # Convert to hours
axes[1,0].plot(range(len(cumulative)), cumulative)
axes[1,0].set_title('Cumulative Duration')
axes[1,0].set_xlabel('Sample Index')
axes[1,0].set_ylabel('Cumulative Hours')
# Duration percentiles
percentiles = [10, 25, 50, 75, 90, 95, 99]
duration_percentiles = [np.percentile(self.df['duration'], p) for p in percentiles]
axes[1,1].bar(range(len(percentiles)), duration_percentiles,
color='lightcoral', alpha=0.7)
axes[1,1].set_title('Duration Percentiles')
axes[1,1].set_xlabel('Percentile')
axes[1,1].set_ylabel('Duration (seconds)')
axes[1,1].set_xticks(range(len(percentiles)))
axes[1,1].set_xticklabels([f'{p}th' for p in percentiles])
plt.tight_layout()
plt.savefig(self.output_dir / 'duration_analysis.png', dpi=300, bbox_inches='tight')
plt.close()
def plot_demographic_analysis(self):
"""Gender and age analysis"""
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('Demographic Analysis', fontsize=16, fontweight='bold')
# Gender pie chart
gender_counts = self.df['gender'].value_counts()
colors = ['lightblue', 'lightpink', 'lightgray']
axes[0,0].pie(gender_counts.values, labels=gender_counts.index, autopct='%1.1f%%',
colors=colors[:len(gender_counts)], startangle=90)
axes[0,0].set_title('Gender Distribution')
# Age distribution
age_counts = self.df['age'].value_counts()
axes[0,1].bar(age_counts.index, age_counts.values, color='lightgreen', alpha=0.7)
axes[0,1].set_title('Age Distribution')
axes[0,1].tick_params(axis='x', rotation=45)
axes[0,1].set_ylabel('Count')
# Gender by dataset
gender_dataset = pd.crosstab(self.df['dataset'], self.df['gender'])
gender_dataset.plot(kind='bar', stacked=True, ax=axes[1,0],
color=['lightblue', 'lightpink', 'lightgray'])
axes[1,0].set_title('Gender by Dataset')
axes[1,0].tick_params(axis='x', rotation=45)
axes[1,0].legend(title='Gender')
# Age by gender heatmap
age_gender = pd.crosstab(self.df['age'], self.df['gender'])
sns.heatmap(age_gender, annot=True, fmt='d', cmap='YlOrRd', ax=axes[1,1])
axes[1,1].set_title('Age vs Gender Heatmap')
plt.tight_layout()
plt.savefig(self.output_dir / 'demographic_analysis.png', dpi=300, bbox_inches='tight')
plt.close()
def plot_accent_analysis(self):
"""Accent distribution analysis"""
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
fig.suptitle('Accent Analysis', fontsize=16, fontweight='bold')
# Top 20 accents
top_accents = self.df['accent'].value_counts().head(20)
axes[0,0].barh(range(len(top_accents)), top_accents.values, color='coral', alpha=0.7)
axes[0,0].set_yticks(range(len(top_accents)))
axes[0,0].set_yticklabels(top_accents.index, fontsize=8)
axes[0,0].set_title('Top 20 Accents')
axes[0,0].set_xlabel('Count')
# Accent diversity by dataset
accent_diversity = self.df.groupby('dataset')['accent'].nunique().sort_values(ascending=False)
axes[0,1].bar(accent_diversity.index, accent_diversity.values, color='lightsteelblue', alpha=0.7)
axes[0,1].set_title('Accent Diversity by Dataset')
axes[0,1].set_ylabel('Unique Accents')
axes[0,1].tick_params(axis='x', rotation=45)
# Regional accent groups
regional_groups = self.categorize_accents()
regional_counts = pd.Series(regional_groups).value_counts()
axes[1,0].pie(regional_counts.values, labels=regional_counts.index, autopct='%1.1f%%',
startangle=90)
axes[1,0].set_title('Regional Accent Groups')
# Accent frequency distribution
accent_freq = self.df['accent'].value_counts()
axes[1,1].hist(accent_freq.values, bins=30, alpha=0.7, color='gold', edgecolor='black')
axes[1,1].set_title('Accent Frequency Distribution')
axes[1,1].set_xlabel('Samples per Accent')
axes[1,1].set_ylabel('Number of Accents')
axes[1,1].set_yscale('log')
plt.tight_layout()
plt.savefig(self.output_dir / 'accent_analysis.png', dpi=300, bbox_inches='tight')
plt.close()
def categorize_accents(self):
"""Categorize accents by region"""
accent_map = {}
for accent in self.df['accent'].unique():
accent_lower = accent.lower()
if any(term in accent_lower for term in ['american', 'us', 'california', 'texas', 'new york']):
accent_map[accent] = 'North American'
elif any(term in accent_lower for term in ['british', 'english', 'scottish', 'welsh', 'irish']):
accent_map[accent] = 'British Isles'
elif any(term in accent_lower for term in ['australian', 'new zealand']):
accent_map[accent] = 'Oceanic'
elif any(term in accent_lower for term in ['indian', 'south asian']):
accent_map[accent] = 'South Asian'
elif any(term in accent_lower for term in ['african', 'south african']):
accent_map[accent] = 'African'
elif any(term in accent_lower for term in ['japanese', 'chinese', 'korean', 'asian']):
accent_map[accent] = 'East Asian'
elif any(term in accent_lower for term in ['european', 'german', 'french', 'spanish', 'italian']):
accent_map[accent] = 'European'
else:
accent_map[accent] = 'Other'
return [accent_map[accent] for accent in self.df['accent']]
def plot_dataset_analysis(self):
"""Dataset source analysis"""
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('Dataset Source Analysis', fontsize=16, fontweight='bold')
# Dataset distribution pie chart
dataset_counts = self.df['dataset'].value_counts()
axes[0,0].pie(dataset_counts.values, labels=dataset_counts.index, autopct='%1.1f%%',
startangle=90)
axes[0,0].set_title('Dataset Distribution')
# Speakers per dataset
speakers_per_dataset = self.df.groupby('dataset')['speaker_id'].nunique()
axes[0,1].bar(speakers_per_dataset.index, speakers_per_dataset.values,
color='lightseagreen', alpha=0.7)
axes[0,1].set_title('Unique Speakers per Dataset')
axes[0,1].tick_params(axis='x', rotation=45)
axes[0,1].set_ylabel('Unique Speakers')
# Average duration by dataset
avg_duration = self.df.groupby('dataset')['duration'].mean()
axes[1,0].bar(avg_duration.index, avg_duration.values, color='plum', alpha=0.7)
axes[1,0].set_title('Average Duration by Dataset')
axes[1,0].tick_params(axis='x', rotation=45)
axes[1,0].set_ylabel('Average Duration (seconds)')
# Total duration by dataset
total_duration = self.df.groupby('dataset')['duration'].sum() / 3600 # Convert to hours
axes[1,1].bar(total_duration.index, total_duration.values, color='khaki', alpha=0.7)
axes[1,1].set_title('Total Duration by Dataset (Hours)')
axes[1,1].tick_params(axis='x', rotation=45)
axes[1,1].set_ylabel('Total Hours')
plt.tight_layout()
plt.savefig(self.output_dir / 'dataset_analysis.png', dpi=300, bbox_inches='tight')
plt.close()
def plot_text_analysis(self):
"""Text content analysis"""
# Calculate text metrics
self.df['transcript_length'] = self.df['transcript'].str.len()
self.df['word_count'] = self.df['transcript'].str.split().str.len()
self.df['description_length'] = self.df['voice_description'].str.len()
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('Text Content Analysis', fontsize=16, fontweight='bold')
# Transcript length distribution
axes[0,0].hist(self.df['transcript_length'], bins=50, alpha=0.7, color='mediumpurple', edgecolor='black')
axes[0,0].set_title('Transcript Length Distribution')
axes[0,0].set_xlabel('Character Count')
axes[0,0].set_ylabel('Frequency')
# Word count distribution
axes[0,1].hist(self.df['word_count'], bins=50, alpha=0.7, color='orange', edgecolor='black')
axes[0,1].set_title('Word Count Distribution')
axes[0,1].set_xlabel('Word Count')
axes[0,1].set_ylabel('Frequency')
# Voice description length
axes[1,0].hist(self.df['description_length'], bins=50, alpha=0.7, color='cyan', edgecolor='black')
axes[1,0].set_title('Voice Description Length')
axes[1,0].set_xlabel('Character Count')
axes[1,0].set_ylabel('Frequency')
# Words per second (speaking rate)
self.df['speaking_rate'] = self.df['word_count'] / self.df['duration'] * 60 # WPM
axes[1,1].hist(self.df['speaking_rate'].replace([np.inf, -np.inf], np.nan).dropna(),
bins=50, alpha=0.7, color='lightgray', edgecolor='black')
axes[1,1].set_title('Speaking Rate (Words per Minute)')
axes[1,1].set_xlabel('WPM')
axes[1,1].set_ylabel('Frequency')
plt.tight_layout()
plt.savefig(self.output_dir / 'text_analysis.png', dpi=300, bbox_inches='tight')
plt.close()
def plot_correlation_analysis(self):
"""Correlation analysis between numerical features"""
numerical_cols = ['duration', 'transcript_length', 'word_count', 'description_length', 'speaking_rate']
correlation_data = self.df[numerical_cols].corr()
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_data, annot=True, cmap='coolwarm', center=0,
square=True, linewidths=0.5)
plt.title('Feature Correlation Matrix', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.savefig(self.output_dir / 'correlation_analysis.png', dpi=300, bbox_inches='tight')
plt.close()
def plot_quality_metrics(self):
"""Dataset quality and completeness metrics"""
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('Dataset Quality Metrics', fontsize=16, fontweight='bold')
# Missing values
missing_data = self.df.isnull().sum()
if missing_data.sum() > 0:
axes[0,0].bar(missing_data.index, missing_data.values, color='red', alpha=0.7)
axes[0,0].set_title('Missing Values by Column')
axes[0,0].tick_params(axis='x', rotation=45)
else:
axes[0,0].text(0.5, 0.5, 'No Missing Values!', ha='center', va='center',
fontsize=14, color='green', weight='bold')
axes[0,0].set_title('Missing Values by Column')
# Unknown/empty values
unknown_counts = {}
for col in ['gender', 'age', 'accent']:
unknown_counts[col] = (self.df[col] == 'unknown').sum()
axes[0,1].bar(unknown_counts.keys(), unknown_counts.values(), color='orange', alpha=0.7)
axes[0,1].set_title('Unknown Values Count')
axes[0,1].set_ylabel('Count')
# Duration outliers
Q1 = self.df['duration'].quantile(0.25)
Q3 = self.df['duration'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = self.df[(self.df['duration'] < lower_bound) | (self.df['duration'] > upper_bound)]
axes[1,0].scatter(range(len(self.df)), self.df['duration'], alpha=0.5, s=1)
axes[1,0].axhline(upper_bound, color='red', linestyle='--', label=f'Upper bound: {upper_bound:.1f}s')
axes[1,0].axhline(lower_bound, color='red', linestyle='--', label=f'Lower bound: {lower_bound:.1f}s')
axes[1,0].set_title(f'Duration Outliers ({len(outliers)} outliers)')
axes[1,0].set_xlabel('Sample Index')
axes[1,0].set_ylabel('Duration (seconds)')
axes[1,0].legend()
# Data completeness score
completeness_scores = {}
for col in ['gender', 'age', 'accent', 'transcript', 'voice_description']:
if col in ['gender', 'age', 'accent']:
completeness_scores[col] = ((self.df[col] != 'unknown').sum() / len(self.df)) * 100
else:
completeness_scores[col] = ((self.df[col].notna() & (self.df[col] != '')).sum() / len(self.df)) * 100
axes[1,1].bar(completeness_scores.keys(), completeness_scores.values(),
color='green', alpha=0.7)
axes[1,1].set_title('Data Completeness (%)')
axes[1,1].set_ylabel('Completeness %')
axes[1,1].tick_params(axis='x', rotation=45)
axes[1,1].set_ylim(0, 105)
plt.tight_layout()
plt.savefig(self.output_dir / 'quality_metrics.png', dpi=300, bbox_inches='tight')
plt.close()
def generate_report(self):
"""Generate comprehensive analysis report"""
stats = self.basic_statistics()
print("\n🎯 Generating comprehensive analysis...")
# Generate all visualizations
self.plot_duration_analysis()
print("✅ Duration analysis complete")
self.plot_demographic_analysis()
print("✅ Demographic analysis complete")
self.plot_accent_analysis()
print("✅ Accent analysis complete")
self.plot_dataset_analysis()
print("✅ Dataset analysis complete")
self.plot_text_analysis()
print("✅ Text analysis complete")
self.plot_correlation_analysis()
print("✅ Correlation analysis complete")
self.plot_quality_metrics()
print("✅ Quality metrics complete")
# Create summary report
self.create_summary_report(stats)
print("✅ Summary report generated")
print(f"\n🎉 Analysis complete! All files saved to: {self.output_dir}")
print(f"📊 Generated {len(list(self.output_dir.glob('*.png')))} visualization files")
def create_summary_report(self, stats):
"""Create text summary report"""
report = f"""
VoicePersona Dataset Analysis Report
====================================
Dataset Overview:
- Total Samples: {stats['total_samples']:,}
- Unique Speakers: {stats['unique_speakers']:,}
- Total Duration: {stats['total_duration_hours']:.1f} hours
- Average Duration: {stats['avg_duration_seconds']:.1f} seconds
- Unique Accents: {stats['unique_accents']}
Dataset Distribution:
{chr(10).join([f"- {k}: {v:,} samples" for k, v in stats['datasets'].items()])}
Gender Distribution:
{chr(10).join([f"- {k}: {v:,} samples" for k, v in stats['genders'].items()])}
Age Distribution:
{chr(10).join([f"- {k}: {v:,} samples" for k, v in stats['age_groups'].items()])}
Top 10 Accents:
{chr(10).join([f"- {k}: {v:,} samples" for k, v in stats['top_accents'].items()])}
Text Metrics:
- Average Transcript Length: {self.df['transcript_length'].mean():.0f} characters
- Average Word Count: {self.df['word_count'].mean():.0f} words
- Average Description Length: {self.df['description_length'].mean():.0f} characters
- Average Speaking Rate: {self.df['speaking_rate'].mean():.0f} WPM
Quality Metrics:
- Missing Values: {self.df.isnull().sum().sum()}
- Unknown Genders: {(self.df['gender'] == 'unknown').sum()}
- Unknown Ages: {(self.df['age'] == 'unknown').sum()}
- Unknown Accents: {(self.df['accent'] == 'unknown').sum()}
Files Generated:
- duration_analysis.png: Audio duration distributions and statistics
- demographic_analysis.png: Gender and age breakdowns
- accent_analysis.png: Accent distributions and regional groupings
- dataset_analysis.png: Source dataset comparisons
- text_analysis.png: Transcript and description analysis
- correlation_analysis.png: Feature correlation heatmap
- quality_metrics.png: Data quality and completeness metrics
- statistics.json: Raw statistics in JSON format
"""
with open(self.output_dir / "analysis_report.txt", 'w') as f:
f.write(report)
def main():
print("🎯 VoicePersona Dataset Analyzer")
print("=" * 50)
analyzer = VoicePersonaAnalyzer()
analyzer.generate_report()
if __name__ == "__main__":
main()
"""
8 Analysis Categories:
Duration Analysis: Histograms, box plots, percentiles, cumulative plots
Demographics: Gender pie charts, age distributions, cross-tabulations
Accent Analysis: Top 20 accents, regional groupings, diversity metrics
Dataset Sources: Distribution comparisons, speaker counts, duration totals
Text Content: Transcript lengths, word counts, speaking rates
Correlations: Feature correlation heatmaps
Quality Metrics: Missing values, outliers, completeness scores
Summary Report: Comprehensive text statistics
Generated Files:
7 PNG visualization files
statistics.json with raw data
analysis_report.txt with summary
"""