چرا نمودار فراوانیتان خواننده را گمراه میکند؟
آیا تا حالا دادههایتان را رسم کردید ولی بیننده نفهمید چه میخواهید بگویید؟ اینجا دقیقاً همانجایی است که باید بایستید.
بسیاری از ما فکر میکنیم کافی است دادهها را توی اکسل یا پایتون بریزیم، یک نمودار هیستوگرام یا میلهای بکشیم و تمام. اما واقعیت این است که نمودار فراوانی یکی از رایجترین ابزارهای بصریسازی داده، همزمان یکی از خطرناکترینهاست. یک انتخاب اشتباه در بازه کلاسها، مقیاس محورها، یا حتی ترتیب نمایش میتواند تصویر کاملاً متفاوتی از واقعیت نشان دهد و مخاطب را به نتیجهگیری غلط بکشاند.
چرا این اتفاق میافتد؟
دادههای خام معمولاً خاموش و بیرحم هستند، اما وقتی آنها را به شکل نمودار درمیآوریم، ناگهان داستانسرایی میکنند. مشکل اینجاست که گاهی داستان ما، داستان واقعی دادهها نیست. مثلاً:
- بازههای کلاس (Bin width) خیلی بزرگ انتخاب کنیم → جزئیات مهم محو میشوند.
- بازهها خیلی کوچک باشند → نمودار شلوغ و پرنوسان میشود و الگوهای اصلی گم میشوند.
- محور عمودی را از صفر شروع نکنیم → تفاوتهای کوچک، بزرگنمایی میشوند.
- دادههای ناهنجار (Outlier) را نادیده بگیریم یا بیش از حد برجسته کنیم.
فوق العاده به کارت میاد: لیست در پایتون چیست؟ تفاوت با Tuple و List
نتیجه؟ مخاطب (مدیر، مشتری، دانشجو یا حتی خودتان) تصوری غلط از توزیع دادهها، میانگین، پراکندگی یا روند پیدا میکند. تصمیمگیریهای مهم روی پایهای لرزان بنا میشوند.
در این مقاله میخواهیم دقیقاً این دامها را بشناسیم و راهفرار از آنها را یاد بگیریم. خواهیم دید:
- چگونه بازههای کلاس مناسب انتخاب کنیم (قوانین Sturges، Scott و Freedman-Diaconis).
- چه زمانی از هیستوگرام به جای آن از نمودار چگالی (Kernel Density) یا جعبهای (Box Plot) استفاده کنیم.
- ترفندهای بصریسازی که شفافیت را افزایش میدهند نه ابهام را.
- مثالهای واقعی از دادههای روزمره (فروش، نمرات، زمان پاسخگویی و غیره) که با یک تنظیم ساده، داستانشان کاملاً تغییر کرد.
اگر خسته شدهاید از اینکه نمودارهایتان «خوب به نظر برسند» اما «پیام غلط» بدهند، این مقاله برای شماست. بیایید با هم یاد بگیریم چطور دادهها را نه فقط نمایش دهیم، بلکه صادقانه و قانعکننده روایت کنیم.

نمودار فراوانی چیست و چه زمانی جایگزین نمودار میلهای است؟
فراوانی یعنی تعداد تکرار هر مقدار در یک ستون داده. نمودار فراوانی (Histogram) این تکرارها را در بازههای عددی نشان میدهد. اما تفاوت کلیدی با نمودار میلهای معمولی: محور افقی در Histogram پیوسته است، نه گسسته.
وقتی سن ۲۵۰ نفر کاربر یک اپلیکیشن فیتنس را دارید، نمودار میلهای سن هر فرد را جداگانه نشان میدهد. Histogram آن را در بازههای ۲۰-۳۰، ۳۰-۴۰ و… خلاصه میکند. اگر هدفتان الگوی توزیع است (مثلاً آیا اکثر کاربران ۲۰ تا ۳۵ سال هستند؟)، Histogram انتخاب درستی است.
تفاوت در یک نگاه
| ویژگی | نمودار میلهای (Bar) | نمودار فراوانی (Histogram) |
|---|---|---|
| نوع داده | دستهای (رشتهای) | عددی پیوسته |
| فاصله بین میلهها | ثابت و مشخص | صفر (میلهها کنار هم) |
| هدف اصلی | مقایسه مقادیر | دیدن توزیع و شکل دادهها |
| مثال کاربردی | فروش ۵ محصول مختلف | توزیع سن یا درآمد مشتریان |
رسم نمودار فراوانی در پایتون: سه روش عملی

روش اول: Matplotlib — کنترل کامل، کد بیشتر
Python
import matplotlib.pyplot as plt
import numpy as np
# داده واقعی: زمان مطالعه روزانه ۲۰۰ دانشجو (دقیقه)
np.random.seed(42)
study_time = np.random.normal(loc=120, scale=40, size=200)
study_time = np.clip(study_time, 30, 300) # محدود کردن بین ۳۰ تا ۳۰۰ دقیقه
plt.figure(figsize=(10, 6))
plt.hist(study_time, bins=15, color=’#2E86AB’, edgecolor=’white’, alpha=0.85)
plt.title(‘توزیع زمان مطالعه روزانه دانشجویان’, fontsize=14, pad=15)
plt.xlabel(‘دقیقه’, fontsize=12)
plt.ylabel(‘تعداد دانشجو’, fontsize=12)
plt.grid(axis=’y’, alpha=0.3, linestyle=’–‘)
# اضافه کردن خط میانگین
mean_val = np.mean(study_time)
plt.axvline(mean_val, color=’#F24236′, linestyle=’–‘, linewidth=2,
label=f’میانگین: {mean_val:.1f} دقیقه’)
plt.legend()
plt.tight_layout()
plt.show()
نکتهای که معمولاً گفته نمیشود: پارامتر bins فقط یک عدد نیست. میتوانید لیستی از مرزها بدهید: bins=[0, 60, 90, 120, 180, 300] — این برای دادههایی که مرزهای طبیعی دارند (مثلاً نمرات دانشگاهی یا ساعات کاری) بسیار خواناتر است.
روش دوم: Seaborn — زیباتر با کد کمتر
Python
import seaborn as sns
sns.set_theme(style=”whitegrid”)
plt.figure(figsize=(10, 6))
sns.histplot(data=study_time, bins=15, kde=True, color=’#2E86AB’)
plt.title(‘توزیع زمان مطالعه + منحنی چگالی’, fontsize=14)
plt.xlabel(‘دقیقه’)
plt.ylabel(‘فراوانی’)
plt.show()
kde=True یک منحنی چگالی احتمال روی Histogram میکشد. این منحنی به بیننده کمک میکند بفهمد دادهها واقعاً توزیع نرمال دارند یا دو قله (bimodal) هستند.
روش سوم: Pandas — سریعترین راه برای بررسی اولیه
Python
import pandas as pd
df = pd.DataFrame({‘study_time’: study_time})
df[‘study_time’].hist(bins=15, figsize=(10, 6), color=’#2E86AB’)
plt.show()
این روش برای EDA سریع عالی است، ولی برای ارائه نهایی کمی خام به نظر میرسد.

رسم چند نمودار در یک شکل: Subplotها
اینجاست که کار جدی میشود. فرض کنید میخواهید توزیع زمان مطالعه را برای سه رشته تحصیلی مختلف مقایسه کنید.
طرح ۱×۳: سه نمودار کنار هم
Python
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
# دادههای سه رشته: مهندسی، پزشکی، حقوق
eng = np.random.normal(100, 30, 200)
med = np.random.normal(180, 25, 200)
law = np.random.normal(140, 35, 200)
fig, axes = plt.subplots(1, 3, figsize=(15, 5), sharey=True)
titles = [‘مهندسی’, ‘پزشکی’, ‘حقوق’]
colors = [‘#2E86AB’, ‘#A23B72’, ‘#F18F01’]
datasets = [eng, med, law]
for ax, data, title, color in zip(axes, datasets, titles, colors):
ax.hist(data, bins=12, color=color, edgecolor=’white’, alpha=0.85)
ax.set_title(title, fontsize=12, pad=10)
ax.set_xlabel(‘دقیقه مطالعه’)
ax.axvline(np.mean(data), color=’red’, linestyle=’–‘, linewidth=1.5)
axes[0].set_ylabel(‘تعداد دانشجو’)
fig.suptitle(‘مقایسه توزیع زمان مطالعه در سه رشته’, fontsize=14, y=1.02)
plt.tight_layout()
plt.show()
sharey=True باعث میشود مقیاس محور Y در هر سه نمودار یکسان باشد. بدون این پارامتر، مقایسه دیداری غیرممکن میشود — اشتباهی که در بسیاری از گزارشها دیده میشود.
طرح ۲×۲: چهار نمودار در یک شکل
Python
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# نمودار ۱: Histogram ساده
axes[0, 0].hist(eng, bins=15, color=’#2E86AB’, alpha=0.8)
axes[0, 0].set_title(‘Histogram مهندسی’)
# نمودار ۲: Histogram با شفافیت برای همپوشانی
axes[0, 1].hist(eng, bins=15, alpha=0.5, label=’مهندسی’, color=’#2E86AB’)
axes[0, 1].hist(med, bins=15, alpha=0.5, label=’پزشکی’, color=’#A23B72′)
axes[0, 1].set_title(‘همپوشانی دو رشته’)
axes[0, 1].legend()
# نمودار ۳: stacked histogram
axes[1, 0].hist([eng, med], bins=15, stacked=True,
color=[‘#2E86AB’, ‘#A23B72’], label=[‘مهندسی’, ‘پزشکی’])
axes[1, 0].set_title(‘Histogram انباشته’)
axes[1, 0].legend()
# نمودار ۴: Histogram با density (نرمالشده)
axes[1, 1].hist(eng, bins=15, density=True, alpha=0.7, color=’#2E86AB’)
axes[1, 1].set_title(‘Histogram نرمالشده (چگالی)’)
axes[1, 1].set_ylabel(‘چگالی’)
plt.tight_layout()
plt.show()

اشتباهاتی که Histogram شما را بیارزش میکنند
- تعداد bins اشتباه: ۵ bins برای ۱۰۰۰ داده خیلی کم است؛ ۱۰۰ bins برای ۵۰ داده خیلی زیاد. قاعده سرانگشتی: تعداد bins ≈ √تعداد دادهها.
- عدم ذکر واحد محورها: Histogram بدون واحد محور X فقط یک شکل رنگی است.
- همپوشانی بدون شفافیت: اگر دو Histogram را با alpha پایین نکشید، میلههای پشتسرهم پنهان میشوند.
- استفاده از Histogram برای دادههای دستهای: سناریویی که در آن رنگها (قرمز، آبی، سبز) را در Histogram رسم میکنید. این دادهها دستهای هستند؛ از نمودار میلهای استفاده کنید.
به دردت میخوره : 3 سایت رایگان برای اجرای کدهای پایتون
سوالات متداول
۱. چطور تعداد مناسب bins را پیدا کنم؟
قانون استورجز (Sturges): bins = 1 + 3.322 * log10(n) که n تعداد دادههاست. در پایتون میتوانید از bins=’auto’ در Matplotlib استفاده کنید که این را خودش حساب میکند.
۲. آیا میتوانم Histogram را به صورت افقی رسم کنم؟
بله. در Matplotlib پارامتر orientation=’horizontal’ را به plt.hist() اضافه کنید. برای دادههایی که برچسبهای طولانی دارند (مثلاً نام شهرها)، این کار خوانایی را افزایش میدهد.
۳. چطور دو Histogram را در یک محور رسم کنم ولی مقیاسهای متفاوت داشته باشند؟
از twinx() استفاده کنید. یک محور جدید بسازید که محور Y آن مستقل باشد. این برای مقایسه فراوانی مطلق با چگالی کاربرد دارد.
۴. چرا KDE من صاف (flat) به نظر میرسد؟
پارامتر bw_adjust در Seaborn را کم کنید (مثلاً ۰.۵). bandwidth بالا باعث میشود منحنی چگالی جزئیات را از دست بدهد.
۵. آیا میتوانم رنگ هر میله را بر اساس ارتفاع آن تغییر دهم؟
بله. از plt.bar() به جای plt.hist() استفاده کنید تا به مقادیر هر میله دسترسی داشته باشید، سپس با یک colormap رنگآمیزی کنید.
۶. Subplotها را چطر در یک فایل PNG با کیفیت بالا ذخیره کنم؟
قبل از plt.show() این را اضافه کنید: plt.savefig(‘output.png’, dpi=300, bbox_inches=’tight’). bbox_inches=’tight’ فضای خالی اضافی اطراف شکل را حذف میکند.

جمعبندی: گام بعدی شما
نمودار فراوانی فقط یک شکل نیست؛ ابزاری برای پرسیدن سوال درست از دادههاست. قبل از رسم هر Histogram، از خودتان بپرسید: «من دنبال الگوی توزیع هستم یا مقایسه مقادیر؟» اگر پاسخ دوم است، برگردید و نمودار میلهای بکشید.
گام بعدی: یک داده واقعی (مثلاً فایل CSV فروش ۳ ماه اخیر) باز کنید. ستون «مبلغ سفارش» را انتخاب کنید. آن را در ۴ subplot رسم کنید: Histogram معمولی، Histogram با KDE، stackedHistogram بر اساس دستهبندی مشتریان، و نمودار جعبهای (boxplot) برای مقایسه. این چهار نمودار را کنار هم بگذارید و به مدیرتان نشان دهید. تفاوت را خواهید دید.
توصیه شخصی: سالها پیش گزارشی دیدم که در آن فروش یک سال را با Histogram رسم کرده بودند. مشکل این بود که محور X ماههای سال بود — دادهای کاملاً دستهای. بیننده فکر میکرد فروش در «بازه» ماههای تابستان بیشتر است، در حالی که مقصد نویسنده مقایسه ماه به ماه بود. از آن روز، همیشه یک بار دیگر محور X را چک میکنم. شما هم این عادت را بسازید.










