मुख्य सामग्री पर जाएँ

Craft Beers का Exploratory Data Analysis: Data Profiling

इस ट्यूटोरियल में, आप Python में exploratory data analysis (EDA) के बारे में सीखेंगे, और खास तौर पर pandas के साथ data profiling के बारे में।
· 14 मि॰ पढ़ें

AI के साथ खोजें

संपादक की टिप्पणी: Jean-Nicholas Hould मॉन्ट्रियल में Intel Security के डेटा वैज्ञानिक हैं और वे अपने ब्लॉग पर डेटा साइंस शुरू करने का तरीका सिखाते हैं।

Exploratory data analysis (EDA) एक सांख्यिकीय तरीका है जिसका उद्देश्य किसी डेटासेट की खोज करना और उसका सार प्रस्तुत करना होता है। डेटा साइंस की इस अवस्था में, आप अपने डेटासेट की संरचना, चर (variables) और उनके संबंधों का अन्वेषण करना चाहते हैं।

इस पोस्ट में, आप exploratory data analysis के एक पहलू पर ध्यान देंगे: data profiling।

Data profiling का मकसद वर्णनात्मक आँकड़ों (descriptive statistics) के जरिए आपके डेटासेट का सार निकालना है। आप अपने डेटासेट को बेहतर समझने के लिए अनेक प्रकार के मापों का उपयोग करना चाहेंगे। डेटा प्रकार (data types), missing values, mean, median और standard deviation सिर्फ कुछ ऐसे तत्व हैं जिन्हें किसी डेटासेट की प्रोफाइलिंग करते समय इकट्ठा करना पड़ता है। Data profiling का लक्ष्य अपने डेटा की ठोस समझ बनाना है ताकि बाद में आप अपने डेटा को अलग-अलग तरीकों से query और visualize करना शुरू कर सकें।

यह जानें कि आपका डेटा कहाँ से आता है

किसी भी EDA में कूदने से पहले, आपको उस डेटा की उत्पत्ति के बारे में संभवतः अधिकतम जानकारी होनी चाहिए जिसका आप विश्लेषण कर रहे हैं। आपको समझना होगा कि डेटा कैसे इकट्ठा किया गया और कैसे संसाधित (processed) किया गया। क्या डेटा पर कोई ऐसे पिछले रूपांतरण (transformations) हुए हैं जो आपके विश्लेषण को प्रभावित कर सकते हैं?

आपको अपने डेटासेट पर ये प्रश्नों के उत्तर देने में सक्षम होना चाहिए:

  • इसे कैसे इकट्ठा किया गया?
  • क्या यह एक नमूना है?
  • क्या इसका सही तरीके से नमूना लिया गया था?
  • क्या डेटासेट को किसी भी तरह से रूपांतरित किया गया था?
  • क्या डेटासेट में कुछ ज्ञात समस्याएँ हैं?

यदि आप नहीं समझते कि डेटा कहाँ से आ रहा है, तो आप डेटासेट से कोई सार्थक निष्कर्ष निकालने में कठिनाई महसूस करेंगे। साथ ही आप महत्वपूर्ण विश्लेषणात्मक गलतियाँ करने के जोखिम में भी होंगे।

इसके अतिरिक्त, आपको यह सुनिश्चित करना चाहिए कि डेटासेट एक मानकीकृत ढांचे में संरचित है। अनुशंसित प्रारूप third normal form है, जिसे tidy data भी कहा जाता है। एक “tidy” डेटासेट में निम्नलिखित विशेषताएँ होती हैं:

  • हर variable एक कॉलम बनाता है और उसमें मान (values) होते हैं
  • हर observation एक पंक्ति बनाता है
  • हर प्रकार की observational unit एक टेबल बनाती है

इस मानकीकृत प्रारूप का पालन करना आपके विश्लेषण को तेज करेगा क्योंकि यह कई टूल्स और लाइब्रेरीज़ के साथ संगत रहता है।

Data Profiling

इस पोस्ट में, आप CraftCans वेबसाइट के Craft Beers के एक डेटासेट का उपयोग करेंगे। यह डेटासेट केवल कैन में आने वाली बियरों को शामिल करता है जो संयुक्त राज्य के ब्रुअरीज़ से हैं। वेबसाइट से यह स्पष्ट नहीं है कि यह डेटासेट अमेरिका में बनी हर एक कैन वाली बियर की रिपोर्ट करता है या नहीं। सुरक्षित रहने के लिए, आप इस डेटासेट को एक sample मानेंगे जिसमें पक्षपात (biases) हो सकते हैं।

यहाँ उन डेटासेट्स की संरचना दी गई है जिनका आप उपयोग करेंगे:

Beers:

  • ID: बियर का यूनिक पहचानकर्ता।
  • Name: बियर का नाम।
  • ABV: बियर का alcohol by volume।
  • IBU: बियर के International Bittering Units।
  • Style: बियर की शैली।
  • Ounces: बियर की औंस में मात्रा।

Breweries:

  • ID: ब्रुअरी का यूनिक पहचानकर्ता।
  • Name: ब्रुअरी का नाम।
  • City: शहर जहाँ ब्रुअरी स्थित है।
  • State: राज्य जहाँ ब्रुअरी स्थित है।

Data Types

पहला कदम है अपने डेटासेट की बनावट को समझना।

आप किन variables के साथ काम कर रहे हैं?

आम तौर पर आप डेटा को इन श्रेणियों में बाँध सकते हैं:

  • संख्यात्मक (Numerical)
  • वर्गीकृत (Categorical)
  • पाठ (Text)
  • तिथि (Date)

आप पहले उन डेटासेट्स को इम्पोर्ट करेंगे जिन्हें आप इस रिपॉज़िटरी में पा सकते हैं, pandas की from_csv फ़ंक्शन के साथ। आप विश्लेषण को आगे आसान बनाने के लिए beers और breweries डेटासेट्स को एक साथ जोड़ेंगे।

import pandas as pd

beers = pd.DataFrame.from_csv("https://raw.githubusercontent.com/nickhould/craft-beers-dataset/master/data/craftcans_beers.csv")
breweries = pd.DataFrame.from_csv("https://raw.githubusercontent.com/nickhould/craft-beers-dataset/master/data/craftcans_breweries.csv")

beers_and_breweries = pd.merge(beers, 
                               breweries, 
                               how='inner', 
                               left_on="brewery_id", 
                               right_on="id", 
                               sort=True,
                               suffixes=('_beer', '_brewery'))

pandas लाइब्रेरी के साथ, आप dtypes फ़ंक्शन चला सकते हैं जो हर कॉलम और उसके डेटा टाइप्स की सूची देता है।

beers.dtypes

जो आपको निम्नलिखित परिणाम देता है:

abv           float64
ibu           float64
id              int64
name           object
style          object
brewery_id      int64
ounces        float64
dtype: object

जैसा कि ऊपर दिखता है, यह फ़ंक्शन विभिन्न डेटा टाइप्स का साफ समूह नहीं करता। अलग-अलग संख्यात्मक डेटा टाइप्स (float64 और int64) एक ही श्रेणी में समूहित नहीं होते जैसा हम चाहेंगे। साथ ही, कुछ कॉलम्स को objects के रूप में सूचीबद्ध किया गया है जो बहुत मददगार नहीं है।

इसे दरकिनार करने के लिए, आप अपना फ़ंक्शन बना सकते हैं जो किसी DataFrame के हर कॉलम की श्रेणी निर्धारित करेगा।

def get_var_category(series):
    unique_count = series.nunique(dropna=False)
    total_count = len(series)
    if pd.api.types.is_numeric_dtype(series):
        return 'Numerical'
    elif pd.api.types.is_datetime64_dtype(series):
        return 'Date'
    elif unique_count==total_count:
        return 'Text (Unique)'
    else:
        return 'Categorical'

def print_categories(df):
    for column_name in df.columns:
        print(column_name, ": ", get_var_category(df[column_name]))

Beers Variables

print_categories(beers)

ऊपर दिया गया कमांड आपको निम्नलिखित परिणाम देता है:

abv :  Numerical
ibu :  Numerical
id :  Numerical
name :  Categorical
style :  Categorical
brewery_id :  Numerical
ounces :  Numerical

Breweries Variables

print_categories(breweries)

जो आपको निम्नलिखित परिणाम देता है:

name :  Categorical
city :  Categorical
state :  Categorical
id :  Numerical

इस सूचना के साथ, आप पहले से ही हमारे डेटासेट को बेहतर समझ सकते हैं। आप जानते हैं कि आप केवल categorical और numerical डेटा से निपट रहे हैं। संख्यात्मक variables से mean, standard deviation आदि जैसे कई अलग-अलग माप निकाले जा सकते हैं। Categorical variables आम तौर पर डेटा को सेगमेंट और समूहित करने का एक रोचक तरीका होते हैं। उदाहरण के लिए, आप समझना चाह सकते हैं कि अलग-अलग बियर शैलियों के बीच IBU कैसे भिन्न होता है।

Descriptive Statistics

इस अनुभाग में, आप विभिन्न descriptive statistics से गुजरेंगे जिनका उपयोग हमारे डेटा को बेहतर समझने के लिए किया जा सकता है। आप नोट करेंगे कि इनमें से हर माप अकेले में बहुत मददगार नहीं होता। अलग-अलग मापों के संयोजन से ही आप सबसे अधिक मूल्य निकाल सकते हैं।

आप IBU variable पर ध्यान केंद्रित करेंगे क्योंकि यह एक संख्यात्मक variable है। इस प्रकार के variable में categorical variables की तुलना में मापों की अधिक व्यापक शृंखला उपलब्ध होती है। आप अपने categorical variables पर भी कुछ माप चला सकते हैं, लेकिन आप काफ़ी सीमित रहेंगे।

Length

len फ़ंक्शन किसी Series में observations की संख्या गिनता है। यह फ़ंक्शन सभी observations को गिनेगा, चाहे उनमें missing या null मान हों।

length = len(beers["ibu"])
print(length)

इस Series में हमारे पास कुल 2410 observations हैं।

Count

count फ़ंक्शन किसी Series में non-NA/non-null observations की संख्या लौटाता है।

count = beers["ibu"].count()
print(count)

जैसा कि आप देख सकते हैं, इस Series में आपके पास 1405 non-null observations हैं।

Missing Values

Length और Count के साथ, अब हम missing values की संख्या की गणना कर सकते हैं। Missing values की संख्या Length और Count के बीच का अंतर है।

number_of_missing_values = length - count
pct_of_missing_values = float(number_of_missing_values / length)
pct_of_missing_values = "{0:.1f}%".format(pct_of_missing_values*100)
print(pct_of_missing_values)

Missing values को प्रतिशत के रूप में आउटपुट करने के लिए, आप बस missing values की संख्या को observations की कुल संख्या, यानी length से भाग देते हैं। विभाजन में दशमलव कैप्चर करने के लिए float फ़ंक्शन का उपयोग किया गया है। संख्या को प्रतिशत के रूप में सुव्यवस्थित ढंग से प्रस्तुत करने के लिए format फ़ंक्शन का उपयोग किया गया है।

इस मामले में, IBU variable के लगभग 42% मान गायब हैं। यह आपके लिए जानना महत्वपूर्ण है क्योंकि यह आपके विश्लेषण को प्रभावित करेगा। अधिकांश descriptive statistics इन missing values को नज़रअंदाज़ करेंगे और इससे निश्चित रूप से एक bias आएगा।

न्यूनतम/अधिकतम मान

किसी डेटासेट का न्यूनतम और अधिकतम मान किसी Series पर min और max फ़ंक्शन से आसानी से प्राप्त किया जा सकता है।

print("Minimum value: ", beers["ibu"].min())
print("Maximum value: ", beers["ibu"].max())

न्यूनतम/अधिकतम मान किसी variable में मानों के दायरे (range) को समझने में सहायक होते हैं। इस मामले में, IBU 4 से 138 तक है।

Mode

Mode किसी डेटासेट में सबसे अधिक बार आने वाला मान होता है। इसे किसी Series पर mode फ़ंक्शन से प्राप्त किया जा सकता है।

print(beers["ibu"].mode())

सामान्य वितरण (normal distribution) में, mode mean और median के बराबर होता है।

इस मामले में, IBU variable का mode 20 है। यह हमारे डेटासेट में सबसे अधिक बार आने वाला IBU है।

Mean

Mean केंद्रीय प्रवृत्ति (central tendency) का एक माप है। यह मानों के योग को non-missing observations की संख्या से भाग देने पर प्राप्त होता है।

इसे किसी Series पर mean फ़ंक्शन से प्राप्त किया जा सकता है।

mean = beers["ibu"].mean()

Mean बाह्य मानों (outliers) से प्रभावित हो सकता है। कुछ चरम मान mean को काफ़ी बदल सकते हैं, उसे ऊपर या नीचे खींच सकते हैं।

Median

Median भी केंद्रीय प्रवृत्ति का एक माप है। यह संख्यात्मक मानों की क्रमबद्ध सूची के ठीक मध्य में स्थित संख्या होती है।

median = beers["ibu"].median()

तिरछे (skewed) वितरणों के मामले में, median mean की तुलना में केंद्रीय प्रवृत्ति का कहीं बेहतर माप होता है।

IBU वितरण के मामले में, mean और median समान परिमाण के क्रम में हैं।

Standard Deviation

Standard deviation प्रसरण (dispersion) का एक माप है। उच्च standard deviation इंगित करता है कि डेटा बिंदु मानों की एक व्यापक शृंखला में फैले हुए हैं। Standard deviation उन्हीं इकाइयों में व्यक्त किया जाता है जिनमें मान होते हैं।

standarddev = beers["ibu"].std()

इस मामले में, standard deviation ~26 है। ठीक-ठीक 25.954065911259324। यदि IBU का वितरण normal distribution होता, तो आप जानते कि ~68% observations mean से एक standard deviation के भीतर होते हैं।

Quantile Statistics

Quantiles कट-पॉइंट्स होते हैं जो किसी वितरण को बराबर आकार के हिस्सों में बाँटते हैं। कई quantiles के अपने नाम होते हैं। यदि आप किसी वितरण को चार समान समूहों में बाँटते हैं, तो जो quantile बनता है उसे quartile कहते हैं। आप किसी Series पर quantile फ़ंक्शन का उपयोग कर आसानी से quantiles बना सकते हैं। आप उस फ़ंक्शन को गणना करने के लिए अलग-अलग quantiles वाला एक array पास कर सकते हैं। नीचे के मामले में, हम अपने वितरण को चार समान समूहों में बाँटना चाहते हैं।

quantile = beers["ibu"].quantile([.25, .5, .75])
0.2521.0
0.5035.0
0.7564.0
Name: ibu,dtype: float64

जैसा कि आप ऊपर देख सकते हैं, 50% क्वांटाइल median के बराबर है। यही वह मान है जो डेटासेट को दो बराबर हिस्सों में बाँटता है। आप यह भी नोट कर सकते हैं कि 75% observations 64 IBU के बराबर या उससे नीचे हैं। आगे, 50% वितरण 21 और 64 IBU के बीच स्थित है। यह नोट करना महत्वपूर्ण है कि इन मेट्रिक्स में missing values को शामिल नहीं किया जाता।

Distribution Plots

दृश्यांकन (visualizations) exploratory data analysis में बहुत उपयोगी होते हैं। इस पोस्ट में, हम visualizations के विषय पर विस्तार में नहीं जाएँगे। हालाँकि, data profiling की बात करते समय frequency-distribution plot के महत्व का उल्लेख किए बिना काम नहीं चलता। यह सबसे सरल, फिर भी सबसे शक्तिशाली visualizations में से एक है। यह हमारे डेटासेट में प्रत्येक मान की आवृत्ति (frequency) को दर्शाता है।

यह visualization बनाने के लिए, हम seaborn`` library with thedisplotfunction. This function expects aSeries` जिसका कोई missing value न हो, का उपयोग कर रहे हैं।

import seaborn as sns
sns.set(color_codes=True)
sns.set_palette(sns.color_palette("muted"))

sns.distplot(beers["ibu"].dropna());

distribution plot

इस distribution plot में, आप स्पष्ट रूप से कुछ वे मान देख सकते हैं जिन्हें हमने पहले गणना किया था। न्यूनतम मान 0 IBU के करीब है और अधिकतम मान 140 IBU के करीब है। आप साफ़ देखते हैं कि सबसे अधिक बार आने वाला मान 20 IBU के करीब है। इस जानकारी के अलावा, अब हम 60 IBU के पास एक शिखर (peak) भी देखते हैं।

इस वितरण में दो शिखर क्यों हैं?

इसे क्या समझा सकता है? यह वह पहलू है जिसे हम exploratory data analysis के दूसरे चरण में खोज सकते हैं।

Correlations

Correlations संख्यात्मक variables के बीच संबंध खोजने का एक बेहतरीन तरीका हैं। सहसंबंध (correlation) की गणना करने के कई तरीके हैं। Pearson correlation coefficient एक व्यापक रूप से प्रयुक्त तरीका है जो दो variables के बीच रैखिक निर्भरता (linear dependence) को मापता है। सहसंबंध गुणांक -1 से 1 तक होता है। 1 का सहसंबंध पूर्ण सकारात्मक सहसंबंध है, -1 का पूर्ण नकारात्मक सहसंबंध और 0 का गैर-रैखिक सहसंबंध। हम Series पर corr फ़ंक्शन का उपयोग करके यह गणना कर सकते हैं। डिफ़ॉल्ट रूप से, यह फ़ंक्शन Pearson correlation coefficient की गणना का उपयोग करेगा। इस फ़ंक्शन के साथ अलग-अलग गणना विधियाँ भी इस्तेमाल की जा सकती हैं।

beers[["abv", "ibu", "ounces"]].corr()
 abvibuounces
abv10.6706210.172529
ibu0.67062110.054691
ounces0.1725290.0546911

जैसा कि आप ऊपर देख सकते हैं, IBU का स्वयं के साथ सहसंबंध 1 है। स्पष्ट है, संख्यात्मक variables अपने आप से पूरी तरह सहसंबद्ध होते हैं। और भी दिलचस्प बात यह है कि आप देखते हैं कि ABV और IBU का सहसंबंध 0.670621 है। यह पूर्ण सकारात्मक सहसंबंध नहीं है, फिर भी यह उच्च सहसंबंध है। यह एक दिलचस्प पहलू है जिसे हम आगे और खोज सकते हैं।

गैर-संख्यात्मक variables पर कुछ टिप्पणियाँ

जो मेट्रिक्स पहले निकाले गए हैं वे अधिकांशतः केवल संख्यात्मक मानों पर लागू होते हैं। यदि आप अन्य प्रकार के डेटा, जैसे categorical डेटा से निपट रहे हैं, तब भी आप कुछ रोचक माप एकत्र कर सकते हैं। आप डेटासेट में प्रत्येक मान की आवृत्ति की गणना कर सकते हैं।

DataFrame में describe नाम का एक फ़ंक्शन होता है जो डेटासेट का सार प्रस्तुत करता है। यदि आपके DataFrame में केवल categorical या text मान हैं, तो सारांश विशेष रूप से इस प्रकार के डेटा के लिए अनुकूलित होगा।

beers[["name", "style"]].describe()
 namestyle
count24102405
unique230599
topNonstop Hef HopAmerican IPA
freq12424

Profiling Libraries

जैसा कि आपने ऊपर देखा, descriptive statistics इकट्ठा करना एक थकाऊ प्रक्रिया हो सकती है। सौभाग्य से, ऐसी लाइब्रेरीज़ मौजूद हैं जो आपके लिए सारा डेटा प्रोसेसिंग कर देती हैं। वे आपके डेटा की एक बहुत स्पष्ट प्रोफ़ाइल आउटपुट करती हैं। pandas-profiling उनमें से एक है। यह लाइब्रेरी आपके डेटासेट की out-of-the-box सांख्यिकीय प्रोफाइलिंग प्रदान करती है। चूँकि हमारा डेटासेट tidy और मानकीकृत है, हम इसे सीधे अपनी लाइब्रेरी पर उपयोग कर सकते हैं।

import pandas_profiling 

pandas_profiling.ProfileReport(beers_and_breweries)

और प्रश्न

आम तौर पर, एक बार जब आप अपने डेटासेट की प्रोफाइलिंग कर लेते हैं, तो आपके पास उस पर शुरुआती अवस्था की तुलना में कहीं अधिक प्रश्न होते हैं। यह बहुत अच्छा है क्योंकि ये नए प्रश्न आपकी exploratory data analysis को गति देंगे।

यहाँ कुछ प्रश्न हैं जो हमने यह प्रोफाइलिंग करते समय इकट्ठा किए:

  • IBU मानों में से 41.7% गायब हैं। ऐसा क्यों है? यह हमारे विश्लेषण को कैसे प्रभावित कर सकता है?
  • IBU वितरण में दो शिखर हैं। इसे क्या समझाता है?
  • IBU और ABV के बीच सहसंबंध को क्या समझाता है? इस सहसंबंध में बियर शैली का क्या प्रभाव है?
  • क्या भौगोलिक क्षेत्रों के बीच IBU, ABV या Style में अंतर हैं? East Coast बनाम West Coast के बारे में क्या?

Data profiling एक रैखिक प्रक्रिया नहीं है। जैसे-जैसे आप अपने डेटासेट को फ़िल्टर और सेगमेंट करेंगे, आप उस पर वापस आएँगे और अपने डेटा के उपसमूहों पर descriptive statistics एकत्र करेंगे।

आगे के कदम

इस पोस्ट में, आपने देखा कि किसी डेटासेट की प्रोफाइलिंग कैसे की जाती है। अब आप जान गए हैं कि variables को विशिष्ट data types समूहों में कैसे बाँटा जाता है। आपने डेटासेट पर विभिन्न descriptive statistics की गणना भी की है और समझते हैं कि उन मापों की व्याख्या कैसे की जाती है। अंत में, आपने देखा कि ऐसी लाइब्रेरीज़ हैं जो आपके डेटासेट की प्रोफाइलिंग के लिए प्रोसेसिंग में मदद कर सकती हैं। इससे भी महत्वपूर्ण, आपने अपनी exploratory data analysis को ऊर्जा देने के लिए पहले से कहीं अधिक प्रश्न उत्पन्न किए हैं।

DataCamp का Python Exploratory Data Analysis Tutorial देखें।

विषय