क्या आपने कभी फ्लैट की तलाश की है? क्या आप कुछ मशीन लर्निंग को जोड़ना और एक प्रक्रिया को और अधिक दिलचस्प बनाना चाहेंगे?
आज हम एक इष्टतम फ्लैट खोजने के लिए मशीन लर्निंग लागू करने पर विचार करेंगे।
परिचय
सबसे पहले, मैं इस क्षण को स्पष्ट करना चाहता हूं और समझाता हूं कि "एक इष्टतम फ्लैट" का क्या मतलब है। यह "क्षेत्र", "जिला", "बालकनियों की संख्या" और इसी तरह की विभिन्न विशेषताओं के एक सेट के साथ एक फ्लैट है। और फ्लैट की इन विशेषताओं के लिए, हम एक विशिष्ट मूल्य की उम्मीद करते हैं। एक फ़ंक्शन की तरह दिखता है जो कई मापदंडों को लेता है और एक नंबर देता है। या शायद एक ब्लैक बॉक्स जो कुछ जादू प्रदान करता है।
लेकिन ... बड़ा "लेकिन" है, कभी-कभी आप एक ऐसे फ्लैट का सामना कर सकते हैं जो एक अच्छी भू-स्थिति जैसे कारणों के एक सेट के कारण अतिरंजित है। इसके अलावा, शहर के केंद्र में और शहर के बाहर के जिलों में अधिक प्रतिष्ठित जिले हैं। या ... कभी-कभी लोग अपने अपार्टमेंट को बेचना चाहते हैं क्योंकि वे पृथ्वी के दूसरे बिंदु पर चले जाते हैं। दूसरे शब्दों में, कई कारक हैं जो कीमत को प्रभावित कर सकते हैं। क्या यह परिचित लगता है?
थोड़ा कदम एक तरफ
इससे पहले कि मैं जारी रखूं, मुझे थोड़ा गेय विषयांतर करने दें।
मैं 5 साल के लिए येकातेरिनबर्ग (यूरोप और एशिया के बीच का शहर, 2018 में द फुटबॉल वर्ल्ड चैंपियनशिप आयोजित करने वाले शहरों में से एक) में रहता था।
मुझे इन ठोस जंगलों से प्यार था। और मैं सर्दियों और सार्वजनिक परिवहन के लिए उस शहर से नफरत करता था। यह एक बढ़ता हुआ शहर है और हर महीने हजारों और हजारों फ्लैट बेचे जाने हैं।
हां, यह एक भीड़भाड़ वाला, प्रदूषित शहर है। एक ही समय में - यह एक अचल संपत्ति बाजार का विश्लेषण करने के लिए एक अच्छी जगह है। मुझे इंटरनेट से, फ्लैटों के लिए बहुत सारे विज्ञापन मिले। और मैं उस जानकारी का उपयोग कुछ हद तक करूंगा।
इसके अलावा, मैंने येकातेरिनबर्ग के नक्शे पर विभिन्न प्रस्तावों की कल्पना करने की कोशिश की। हाँ, यह habracut से कैच-आई तस्वीर है, इसे केप्लर.लग पर बनाया गया है

2 हजार से अधिक बेडरूम वाले फ्लैट हैं, जो 2019 के जुलाई में येकातेरिनबर्ग में बेचे गए थे। उनके पास एक अलग कीमत थी, एक मिलियन से लगभग 14 मिलियन रूबल तक।
ये बिंदु उनके भू-स्थिति को संदर्भित करते हैं। मानचित्र पर बिंदुओं का रंग मूल्य का प्रतिनिधित्व करता है, नीले रंग के पास कम कीमत है, उच्च लाल के पास कीमत है। आप इसे ठंडे और गर्म रंगों के साथ एक सादृश्य के रूप में मान सकते हैं, गर्म रंग बड़ा होता है।
कृपया, उस क्षण को याद रखें, रेडर रंग है, उच्चतर किसी चीज का मूल्य है। एक ही विचार नीले रंग के लिए काम करता है लेकिन सबसे कम कीमत की दिशा में।
अब आप चित्र का सामान्य अवलोकन कर रहे हैं और विश्लेषण करने का समय आ रहा है।
लक्ष्य
जब मैं येकातेरिनबर्ग में रहता था तो मुझे क्या चाहिए था? मैंने एक अच्छे फ्लैट की तलाश की, या अगर हम एमएल के संदर्भ में बात करें - मैं एक मॉडल बनाना चाहता था जो मुझे खरीदने के बारे में एक सिफारिश देगा।
एक तरफ, यदि कोई फ्लैट ओवरराइड हो जाता है, तो मॉडल को उस फ्लैट के लिए अपेक्षित मूल्य दिखाते हुए कीमत कम होने की प्रतीक्षा करने की सलाह देनी चाहिए।
दूसरी ओर - यदि बाजार की स्थिति के अनुसार, एक कीमत काफी अच्छी है, तो शायद मुझे उस प्रस्ताव पर विचार करना चाहिए।
बेशक, कुछ भी आदर्श नहीं है और मैं गणना में गलती स्वीकार करने के लिए तैयार था। आमतौर पर इस तरह के कार्य के लिए भविष्यवाणी की औसत त्रुटि होती है और मैं 10% त्रुटि के लिए तैयार था। उदाहरण के लिए, यदि आपके पास 2-3 मिलियन रूसी रूबल हैं, तो आप 200-300 हजार में गलती को अनदेखा कर सकते हैं, आप इसे बर्दाश्त कर सकते हैं। जैसा कि मुझे लग रहा था।
तैयार हो रहा है
जैसा कि मैंने पहले उल्लेख किया है, बहुत सारे अपार्टमेंट थे, चलो उन्हें करीब से देखें।
पीडी के रूप में आयात पांडा
df = pd.read_csv('flats.csv') df.shape

एक महीने के लिए 2310 फ्लैट, हम उससे कुछ उपयोगी निकाल सकते हैं। एक सामान्य डेटा अवलोकन के बारे में क्या?
df.describe()

असाधारण कुछ नहीं है - देशांतर, अक्षांश, एक फ्लैट की कीमत (लेबल " लागत "), और इसी तरह। हां, उस पल के लिए मैंने " कीमत " के बजाय " लागत " का इस्तेमाल किया, मुझे उम्मीद है कि इससे गलतफहमी पैदा नहीं होगी, कृपया उन्हें भी ऐसा ही मानें।
सफाई
क्या हर रिकॉर्ड का एक ही अर्थ होता है? उनमें से कुछ एक क्यूबिकल की तरह फ्लैट्स का प्रतिनिधित्व करते हैं, आप वहां काम कर सकते हैं, लेकिन आप वहां रहना पसंद नहीं करेंगे। वे छोटे तंग कमरे हैं, असली फ्लैट नहीं। उन्हें हटा दें।
df = df[df.total_area >= 20]
फ्लैट की भविष्यवाणी की कीमत अर्थशास्त्र और संबंधित क्षेत्रों में सबसे पुराने मुद्दों से आती है। "एमएल" शब्द से संबंधित कुछ भी नहीं था और लोगों ने वर्ग मीटर / पैरों के आधार पर कीमत का अनुमान लगाने की कोशिश की।
इसलिए, हम इन स्तंभों / लेबल को देखते हैं और उनका वितरण प्राप्त करने का प्रयास करते हैं।
numerical_fields = ['total_area','cost'] for col in numerical_fields: mask = ~np.isnan(df[col]) sns.distplot(df[col][mask], color="r",label=col) plot.show()

खैर ... कुछ खास नहीं है, सामान्य वितरण जैसा दिखता है। शायद हमें गहराई में जाने की जरूरत है?
sns.pairplot(df[numerical_fields])

उफ़ ... कुछ गड़बड़ है। इन क्षेत्रों में स्वच्छ आउटलेयर और फिर से हमारे डेटा का विश्लेषण करने का प्रयास करें।

आउटलेयर चले गए हैं, और अब यह बेहतर दिखता है।
लेबल "वर्ष", जिसे निर्माण के एक वर्ष में इंगित किया गया है, को कुछ अधिक जानकारीपूर्ण में बदलना चाहिए। यह निर्माण की उम्र होने दें, दूसरे शब्दों में एक विशिष्ट घर कैसे पुराना है।
df['age'] = 2019 -df['year']
परिणाम पर एक नजर डालते हैं।
df.head()

सभी प्रकार के डेटा, श्रेणीबद्ध, नैन-मूल्य, पाठ-विवरण और कुछ भू-सूचना (देशांतर और अक्षांश) हैं। आइए हम पिछले वाले को अलग रख दें क्योंकि उस स्तर पर वे बेकार हैं। हम बाद में उनके पास लौट आएंगे।
df.drop(columns=["lon","lat","description"],inplace=True)
श्रेणीबद्ध डेटा
आमतौर पर, श्रेणीबद्ध डेटा के लिए, लोग विभिन्न प्रकार के एन्कोडिंग या कैटबॉस्ट जैसी चीजों का उपयोग करते हैं जो संख्यात्मक चर के साथ उनके साथ काम करने का अवसर प्रदान करते हैं।
लेकिन, क्या हम कुछ अधिक तार्किक और अधिक सहज ज्ञान युक्त उपयोग कर सकते हैं? अब उनके अर्थ को खोए बिना हमारे डेटा को और अधिक समझने का समय है।
जिलों
खैर, बीस से अधिक संभावित जिले हैं, क्या हम अपने मॉडल में 20 से अधिक अतिरिक्त चर जोड़ सकते हैं? बेशक, हम कर सकते थे, लेकिन ... हमें करना चाहिए? हम लोग हैं और हम चीजों की तुलना कर सकते हैं, है ना?
सबसे पहले - प्रत्येक जिला दूसरे के बराबर नहीं है। शहर के केंद्र में एक वर्ग मीटर के लिए कीमतें अधिक है, शहर से आगे - यह घट जाती है। क्या यह तर्कसंगत लगता है? क्या हम उसका उपयोग कर सकते हैं?
हां, निश्चित रूप से हम एक विशिष्ट गुणांक के साथ किसी भी जिले का मिलान कर सकते हैं और आगे का जिला सस्ता फ्लैट हैं।
शहर से मेल खाने और एक अन्य वेब सेवा मानचित्र (आर्कजीआईएस ऑनलाइन) का उपयोग करने के बाद बदल गया है और एक समान दृश्य है

मैंने फ्लैट के विज़ुअलाइज़ेशन के लिए उसी विचार का इस्तेमाल किया। सबसे "प्रतिष्ठित" और "महंगा" जिला लाल और कम से कम नीला रंग में रंगा हुआ है। एक रंग तापमान, क्या आपको इसके बारे में याद है?
इसके अलावा, हमें अपने डेटाफ्रेम पर कुछ हेरफेर करना चाहिए।
district_map = {'alpha': 2, 'beta': 4, ... 'delta':3, ... 'epsilon': 1} df.district = df.district.str.lower() df.replace({"district": district_map}, inplace=True)
फ्लैट की आंतरिक गुणवत्ता का वर्णन करने के लिए उसी दृष्टिकोण का उपयोग किया जाएगा। कभी-कभी इसे कुछ मरम्मत की आवश्यकता होती है, कभी-कभी फ्लैट काफी अच्छी तरह से और रहने के लिए तैयार होता है। और अन्य मामलों में, आपको इसे बेहतर दिखाने के लिए (नल को बदलने के लिए, दीवारों को रंगाने के लिए) अतिरिक्त पैसे खर्च करने चाहिए। वहाँ भी गुणांक का उपयोग किया जा सकता है।
repair = {'A': 1, 'B': 0.6, 'C': 0.7, 'D': 0.8} df.repair.fillna('D', inplace=True) df.replace({"repair": repair}, inplace=True)
वैसे, दीवारों के बारे में। बेशक, यह फ्लैट की कीमत को भी प्रभावित करता है। आधुनिक सामग्री पुराने से बेहतर है, ईंट कंक्रीट से बेहतर है। लकड़ी से दीवारें काफी विवादास्पद क्षण हैं, शायद यह ग्रामीण इलाकों के लिए एक अच्छा विकल्प है, लेकिन शहरी जीवन के लिए इतना अच्छा नहीं है।
हम पहले के समान दृष्टिकोण का उपयोग करते हैं, साथ ही उन पंक्तियों के बारे में एक सुझाव देते हैं जिन्हें हम कुछ भी नहीं जानते हैं। हां, कभी-कभी लोग अपने फ्लैट के बारे में सारी जानकारी नहीं देते हैं। इसके अलावा, इतिहास के आधार पर हम दीवारों की सामग्री के बारे में अनुमान लगाने की कोशिश कर सकते हैं। समय की एक विशिष्ट अवधि में (उदाहरण के लिए ख्रुश्चेव की अग्रणी) - हम निर्माण के लिए विशिष्ट सामग्री के बारे में जानते हैं।
walls_map = {'brick': 1.0, ... 'concrete': 0.8, 'block': 0.8, ... 'monolith': 0.9, 'wood': 0.4} mask = df[df['walls'].isna()][df.year >= 2010].index df.loc[mask, 'walls'] = 'monolith' mask = df[df['walls'].isna()][df.year >= 2000].index df.loc[mask, 'walls'] = 'concrete' mask = df[df['walls'].isna()][df.year >= 1990].index df.loc[mask, 'walls'] = 'block' mask = df[df['walls'].isna()].index df.loc[mask, 'walls'] = 'block' df.replace({"walls": walls_map}, inplace=True) df.drop(columns=['year'],inplace=True)
साथ ही, बालकनी के बारे में जानकारी है। मेरी विनम्र राय में - बालकनी वास्तव में उपयोगी चीज है, इसलिए मैं खुद पर विचार करने में मदद नहीं कर सका।
दुर्भाग्य से, कुछ अशक्त मूल्य हैं। यदि किसी विज्ञापन के लेखक ने इसके बारे में जानकारी की जाँच की है, तो हमारे पास अधिक यथार्थवादी जानकारी होगी।
खैर, अगर कोई जानकारी नहीं है, तो इसका मतलब होगा "एक बालकनी नहीं है"।
df.balcony.fillna(0,inplace=True)
उसके बाद, हम निर्माण के वर्ष के बारे में जानकारी के साथ कॉलम छोड़ते हैं (हमारे पास इसके लिए एक अच्छा विकल्प है)। इसके अलावा, हम इमारत के प्रकार के बारे में जानकारी के साथ कॉलम को हटा देते हैं क्योंकि इसमें बहुत सारे एनएन-मूल्य हैं और मुझे इन अंतरालों को भरने का कोई अवसर नहीं मिला है। और हम NaN के साथ सभी पंक्तियों को छोड़ देते हैं जो हमारे पास है।
df.drop(columns=['type_house'],inplace=True) df = df.astype(np.float64) df.dropna(inplace=True)
जाँच हो रही है
इसलिए ... हमने एक मानक दृष्टिकोण का उपयोग किया और उनके संख्यात्मक प्रतिनिधित्व के लिए श्रेणीबद्ध मूल्यों को प्रतिस्थापित किया। और अब हम अपने डेटा के परिवर्तन के साथ समाप्त हो गए।
डेटा का एक हिस्सा छोड़ दिया गया है, लेकिन सामान्य तौर पर, यह काफी अच्छा डेटासेट है। स्वतंत्र चर के बीच संबंध को देखें।
def show_correlation(df): sns.set(style="whitegrid") corr = df.corr() * 100

एर्म ... यह बहुत दिलचस्प हो गया।
सकारात्मक सहसंबंध
कुल क्षेत्र - बालकनियाँ । क्यों नहीं? अगर हमारा फ्लैट बड़ा है तो बालकनी होगी।
नकारात्मक सहसंबंध
कुल क्षेत्रफल - आयु । नया फ्लैट है, बड़ा रहने के लिए एक क्षेत्र है। ध्वनि तार्किक, नए पुराने की तुलना में अधिक विशाल फ्लैट हैं।
आयु - बालकनी । पुराने फ्लैट कम बालकनियों है यह है। एक अन्य चर के माध्यम से सहसंबंध की तरह लगता है। शायद यह एक त्रिकोण आयु-बालकनी-क्षेत्र है जहां एक चर का दूसरे पर एक अंतर्निहित प्रभाव पड़ता है। कुछ समय के लिए इसे दबाए रखें।
आयु - जिला। पुराना फ्लैट बड़ी संभावना है जिसे अधिक प्रतिष्ठित जिलों में रखा जाएगा। क्या यह केंद्र के पास उच्च मूल्य से संबंधित हो सकता है?
इसके अलावा, हम निर्भर चर के साथ सहसंबंध देख सकते हैं
plt.figure(figsize=(6,6)) corr = df.corr()*100.0 sns.heatmap(corr[['cost']], cmap= sns.diverging_palette(220, 10), center=0, linewidths=1, cbar_kws={"shrink": .7}, annot=True, fmt=".2f")

यहाँ हम चलते हैं ...
फ्लैट और कीमत के क्षेत्र के बीच बहुत मजबूत संबंध। यदि आप रहने के लिए एक बड़ा स्थान चाहते हैं तो इसके लिए अधिक धन की आवश्यकता होगी।
जोड़े " उम्र / लागत " और " जिला / लागत " के बीच एक नकारात्मक सहसंबंध है। एक नए घर में एक फ्लैट पुराने की तुलना में कम सस्ती है। और ग्रामीण इलाकों में फ्लैट सस्ते हैं।
किसी भी तरह, यह स्पष्ट और समझ में आता है, इसलिए मैंने इसके साथ जाने का फैसला किया।
आदर्श
आमतौर पर भविष्यवाणी फ्लैट की कीमत से संबंधित कार्यों के लिए, रैखिक प्रतिगमन का उपयोग करें। पिछले चरण से महत्वपूर्ण सहसंबंध के अनुसार, हम इसका उपयोग करने की कोशिश कर सकते हैं। यह एक वर्कहॉर्स है जो कई कार्यों के लिए उपयुक्त है।
अगली क्रियाओं के लिए हमारा डेटा तैयार करें
from sklearn.model_selection import train_test_split y = df.cost X = df.drop(columns=['cost']) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
इसके अलावा, हम परिणाम की भविष्यवाणी और मूल्यांकन के लिए कुछ सरल कार्य बनाते हैं। चलो मूल्य की भविष्यवाणी करने की हमारी पहली कोशिश करते हैं!
def predict(X, y_test, model): y = model.predict(X) score = round((r2_score(y_test, y) * 100), 2) print(f'Score on {model.__class__.__name__} is {score}') return score def train_model(X, y, regressor): model = regressor.fit(X, y) return model
from sklearn.linear_model import LinearRegression regressor = LinearRegression() model = train_model(X_train, y_train, regressor) predict(X_test, y_test, model)

अच्छी तरह से ... 76.67% सटीकता। यह एक बड़ी संख्या है या नहीं? मेरे हिसाब से यह बुरा नहीं है। इसके अलावा, यह एक अच्छा शुरुआती बिंदु है। बेशक, यह आदर्श नहीं है, और सुधार की क्षमता है।
उसी समय - हमने डेटा के केवल एक हिस्से की भविष्यवाणी करने की कोशिश की। अन्य डेटा के लिए एक ही रणनीति लागू करने के बारे में क्या? हाँ, क्रॉस-सत्यापन के लिए समय।
def do_cross_validation(X, y, model): from sklearn.model_selection import KFold, cross_val_score regressor_name = model.__class__.__name__ fold = KFold(n_splits=10, shuffle=True, random_state=0) scores_on_this_split = cross_val_score(estimator=model, X=X, y=y, cv=fold, scoring='r2') scores_on_this_split = np.round(scores_on_this_split * 100, 2) mean_accuracy = scores_on_this_split.mean() print(f'Crossvaladaion accuracy on {model.__class__.__name__} is {mean_accuracy}') return mean_accuracy do_cross_validation(X, y, model)

क्रॉस-वेलिडेशन का परिणाम है। हम एक और परिणाम लेते हैं। 73 76 से कम है। लेकिन, यह भी एक अच्छा उम्मीदवार है जब तक कि हमारे पास एक बेहतर होगा। इसके अलावा, इसका मतलब है कि एक रैखिक प्रतिगमन हमारे डेटासेट पर काफी स्थिर है।
और अब अंतिम चरण के लिए एक समय है।
हम रैखिक प्रतिगमन - व्याख्यात्मकता की सबसे अच्छी विशेषता को देखेंगे।
मॉडल का यह परिवार, अधिक जटिल लोगों के विपरीत, समझने की बेहतर क्षमता रखता है। गुणांक के साथ बस कुछ संख्याएं हैं और आप अपने संख्याओं को समीकरण में रख सकते हैं, कुछ सरल गणित कर सकते हैं और परिणाम हो सकते हैं।
हमारे मॉडल की व्याख्या करने की कोशिश करते हैं
def estimate_model(model): sns.set(style="white", context="talk") f, ax = plot.subplots(1, 1, figsize=(10, 10), sharex=True) sns.barplot(x=model.coef_, y=X.columns, palette="vlag", ax=ax) for i, v in enumerate(model.coef_.astype(int)): ax.text(v + 3, i + .25, str(v), color='black') ax.set_title(f"Coefficients") estimate_model(regressor)

तस्वीर काफी तार्किक लग रही है। बालकनी / दीवारें / क्षेत्र / मरम्मत एक फ्लैट मूल्य के लिए एक सकारात्मक योगदान देते हैं।
आगे का फ्लैट बड़ा नकारात्मक योगदान है । उम्र के लिए भी लागू। पुराने फ्लैट की कीमत कम होगी।
तो, यह एक आकर्षक यात्रा थी।
हमने जमीन से शुरू किया, मानव दृष्टिकोण (संख्याओं के बजाय डमी चर), जाँच किए गए चर और उनके संबंध के आधार पर डेटा परिवर्तन के लिए अनैतिक दृष्टिकोण का उपयोग करें। उसके बाद, हम अपने सरल मॉडल का निर्माण करते हैं, इसके परीक्षण के लिए क्रॉस-मान्यता का उपयोग करते हैं। और केक पर चेरी के रूप में - मॉडल के आंतरिक पर नजर डालें, जो हमें अपने तरीके के बारे में आत्मविश्वास देता है।
लेकिन! यह हमारी यात्रा खत्म नहीं है बल्कि केवल एक ब्रेक है। हम भविष्य में अपने मॉडल को बदलने की कोशिश करेंगे और शायद (सिर्फ शायद) यह भविष्यवाणी की सटीकता को बढ़ाता है।
पढ़ने के लिए धन्यवाद!
दूसरा भाग है
PS स्रोत डेटा और Ipython- नोटबुक वहाँ स्थित है