Pembelajaran Mesin untuk berburu flat Anda. Bagian 1

Pernahkah Anda mencari flat? Apakah Anda ingin menambahkan beberapa pembelajaran mesin dan membuat proses lebih menarik?


Apartemen di Yekaterinburg

Hari ini kami akan mempertimbangkan menerapkan Pembelajaran Mesin untuk menemukan flat yang optimal.


Pendahuluan


Pertama-tama, saya ingin memperjelas momen ini dan menjelaskan apa arti "flat optimal". Ini adalah flat dengan serangkaian karakteristik yang berbeda seperti "area", "distrik", "jumlah balkon" dan sebagainya. Dan untuk fitur flat ini, kami mengharapkan harga tertentu. Tampak seperti fungsi yang mengambil beberapa parameter dan mengembalikan angka. Atau mungkin kotak hitam yang menyediakan sihir.


Tapi ... ada "tapi" besar, kadang-kadang Anda dapat menghadapi flat yang terlalu mahal karena serangkaian alasan seperti posisi geografis yang baik. Juga, ada distrik yang lebih bergengsi di pusat kota dan distrik di luar kota. Atau ... kadang-kadang orang ingin menjual apartemen mereka karena mereka pindah ke titik lain di Bumi. Dengan kata lain, ada banyak faktor yang dapat mempengaruhi harga. Apakah itu terdengar familier?


Sedikit minggir


Sebelum saya melanjutkan, izinkan saya membuat sedikit penyimpangan lirik.
Saya tinggal di Yekaterinburg (kota antara Eropa dan Asia, salah satu kota yang pernah menyelenggarakan Kejuaraan Dunia Sepakbola pada 2018) selama 5 tahun.


Saya jatuh cinta dengan hutan beton ini. Dan saya benci kota itu untuk musim dingin dan transportasi umum. Ini adalah kota yang berkembang dan setiap bulan ada ribuan dan ribuan flat untuk dijual.


Ya, itu adalah kota yang penuh sesak dan tercemar. Pada saat yang sama - ini adalah tempat yang baik untuk menganalisis pasar real estat. Saya menerima banyak iklan flat, dari Internet. Dan saya akan menggunakan informasi itu lebih jauh.


Juga, saya mencoba memvisualisasikan berbagai tawaran di peta Yekaterinburg. Ya, itu adalah gambar menarik dari habracut, itu dibuat di Kepler.gl


gambar


Ada lebih dari 2 ribu flat 1 kamar tidur yang telah dijual pada bulan Juli 2019 di Yekaterinburg. Mereka memiliki harga yang berbeda, dari kurang dari satu juta hingga hampir 14 juta rubel.


Poin-poin ini merujuk pada posisi geografis mereka. Warna titik pada peta mewakili harga, semakin rendah harga mendekati warna biru, semakin tinggi harga mendekati merah. Anda dapat menganggapnya sebagai analogi dengan warna dingin dan hangat, semakin hangat warna semakin besar harga.
Tolong, ingatlah saat itu, semakin merah warnanya, semakin tinggi nilai sesuatu. Gagasan yang sama berlaku untuk warna biru tetapi ke arah harga terendah.


Sekarang Anda memiliki gambaran umum tentang gambar dan waktu untuk menganalisis akan datang.


Tujuan


Apa yang saya inginkan ketika saya tinggal di Yekaterinburg? Saya mencari flat yang cukup baik, atau jika kita berbicara tentang ML - saya ingin membangun model yang akan memberi saya rekomendasi tentang pembelian.


Di satu sisi, jika flat terlalu mahal, model harus merekomendasikan menunggu penurunan harga dengan menunjukkan harga yang diharapkan untuk flat itu.
Di sisi lain - jika harga cukup bagus, menurut keadaan pasar - mungkin saya harus mempertimbangkan tawaran itu.


Tentu saja, tidak ada yang ideal dan saya siap menerima kesalahan dalam perhitungan. Biasanya, untuk jenis tugas ini gunakan rata-rata kesalahan prediksi dan saya siap untuk kesalahan 10%. Misalnya, jika Anda memiliki 2-3 juta rubel Rusia, Anda dapat mengabaikan kesalahan dalam 200-300 ribu, Anda dapat membelinya. Seperti yang menurut saya.


Siapkan


Seperti yang saya sebutkan sebelumnya, ada banyak apartemen, mari kita lihat dari dekat.
impor panda sebagai pd


df = pd.read_csv('flats.csv') df.shape 

gambar


2310 flat selama satu bulan, kita bisa mengekstraksi sesuatu yang bermanfaat dari itu. Bagaimana dengan gambaran umum data?


 df.describe() 

gambar
Tidak ada sesuatu yang luar biasa - bujur, lintang, harga flat (label " biaya "), dan sebagainya. Ya, untuk saat itu saya menggunakan " biaya " alih-alih " harga ", saya harap itu tidak akan menyebabkan kesalahpahaman, harap menganggapnya sama.


Membersihkan


Apakah setiap rekaman memiliki arti yang sama? Beberapa dari mereka diwakili flat seperti bilik, Anda dapat bekerja di sana, tetapi Anda tidak ingin tinggal di sana. Mereka adalah kamar sempit kecil, bukan flat nyata. Biarkan menghapusnya.


 df = df[df.total_area >= 20] 

Prediksi harga flat berasal dari masalah tertua di bidang ekonomi dan bidang terkait. Tidak ada yang terkait dengan istilah "ML" dan orang-orang mencoba menebak harga berdasarkan meter persegi.
Jadi, kita melihat kolom / label ini dan mencoba untuk mendapatkan distribusi mereka.


 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() 

gambar


Yah ... tidak ada yang istimewa, sepertinya distribusi normal. Mungkin kita perlu masuk lebih dalam?


 sns.pairplot(df[numerical_fields]) 

gambar


Ups ... ada yang salah di sana. Bersihkan pencilan di bidang ini dan coba menganalisis data kami lagi.


 #Remove outliers df = df[abs(df.total_area - df.total_area.mean()) <= (3 * df.total_area.std())] df = df[abs(df.cost - df.cost.mean()) <= (3 * df.cost.std())] #Redraw our data sns.pairplot(df[numerical_fields]) 

gambar


Pencilan telah hilang, dan sekarang terlihat lebih baik.


Transformasi


Label "tahun", yang menunjuk pada tahun konstruksi harus diubah menjadi sesuatu yang lebih informatif. Biarlah itu usia bangunan, dengan kata lain berapa lama rumah tertentu.


 df['age'] = 2019 -df['year'] 

Mari kita lihat hasilnya.


 df.head() 

gambar


Ada semua jenis data, kategorikal, nilai Nan, deskripsi teks dan beberapa informasi geografis (bujur dan lintang). Mari kita kesampingkan yang terakhir karena pada tahap itu mereka tidak berguna. Kami akan kembali kepada mereka nanti.


 df.drop(columns=["lon","lat","description"],inplace=True) 

Data kategorikal


Biasanya, untuk data kategorikal, orang menggunakan berbagai jenis pengkodean atau hal-hal seperti CatBoost yang memberikan peluang untuk bekerja dengannya seperti halnya dengan variabel numerik.
Tapi, bisakah kita menggunakan sesuatu yang lebih logis dan lebih intuitif? Sekaranglah waktunya untuk membuat data kita lebih mudah dipahami tanpa kehilangan arti dari data itu.


Distrik


Ya, ada lebih dari dua puluh kabupaten yang memungkinkan, dapatkah kita menambahkan lebih dari 20 variabel tambahan dalam model kita? Tentu saja, kita bisa, tetapi ... haruskah kita? Kita adalah manusia dan kita dapat membandingkan berbagai hal, bukan?
Pertama-tama - tidak setiap kabupaten setara dengan yang lain. Di pusat kota harga untuk satu meter persegi lebih tinggi, jauh dari pusat kota - itu menjadi menurun. Apakah ini terdengar logis? Bisakah kita menggunakannya?
Ya, pasti kami dapat mencocokkan kabupaten mana pun dengan koefisien tertentu dan kabupaten selanjutnya adalah flat yang lebih murah.


Setelah mencocokkan kota dan menggunakan peta layanan web lain (ArcGIS Online) berubah dan memiliki tampilan yang sama
gambar


Saya menggunakan ide yang sama dengan visualisasi flat. Distrik yang paling "bergengsi" dan "mahal" diwarnai merah dan paling tidak - biru. Temperatur warna, apakah Anda ingat tentang itu?
Juga, kita harus melakukan manipulasi atas kerangka data kita.


 district_map = {'alpha': 2, 'beta': 4, ... 'delta':3, ... 'epsilon': 1} df.district = df.district.str.lower() df.replace({"district": district_map}, inplace=True) 

Pendekatan yang sama akan digunakan untuk menggambarkan kualitas internal flat. Terkadang butuh perbaikan, terkadang flat cukup baik dan siap untuk hidup. Dan dalam kasus lain, Anda harus mengeluarkan uang tambahan untuk membuatnya terlihat lebih baik (untuk mengganti keran, untuk mengecat dinding). Ada juga bisa menggunakan koefisien.


 repair = {'A': 1, 'B': 0.6, 'C': 0.7, 'D': 0.8} df.repair.fillna('D', inplace=True) df.replace({"repair": repair}, inplace=True) 

Ngomong-ngomong, tentang dinding. Tentu saja, itu juga mempengaruhi harga flat. Material modern lebih baik daripada yang tua, bata lebih baik dari beton. Dinding dari kayu adalah momen yang cukup kontroversial, mungkin itu adalah pilihan yang baik untuk pedesaan, tetapi tidak begitu baik untuk kehidupan kota.


Kami menggunakan pendekatan yang sama seperti sebelumnya, ditambah membuat saran tentang baris yang tidak kami ketahui. Ya, terkadang orang tidak memberikan semua informasi tentang flat mereka. Selanjutnya berdasarkan sejarah kita bisa mencoba menebak tentang bahan dinding. Dalam periode waktu tertentu (misalnya periode terkemuka Khrushchev) - kita tahu tentang bahan khas untuk bangunan.


 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) 

Juga, ada informasi tentang balkon. Menurut pendapat saya yang sederhana - balkon adalah hal yang sangat berguna, jadi saya tidak bisa menahan diri untuk mempertimbangkannya.
Sayangnya, ada beberapa nilai null. Jika pembuat iklan memeriksa informasi tentang itu, kami akan mendapatkan informasi yang lebih realistis.
Nah, jika tidak ada informasi itu berarti "tidak ada balkon".


 df.balcony.fillna(0,inplace=True) 

Setelah itu, kami menjatuhkan kolom dengan informasi tentang tahun pembangunan (kami memiliki alternatif yang baik untuk itu). Selain itu, kami menghapus kolom dengan informasi tentang jenis bangunan karena memiliki banyak nilai NaN dan saya belum menemukan peluang untuk mengisi celah ini. Dan kita drop semua baris dengan NaN yang kita miliki.


 df.drop(columns=['type_house'],inplace=True) df = df.astype(np.float64) df.dropna(inplace=True) 

Memeriksa


Jadi ... kami menggunakan pendekatan yang tidak standar dan mengganti nilai kategorikal ke representasi numerik mereka. Dan sekarang kami selesai dengan transformasi data kami.
Sebagian dari data telah dihapus, tetapi secara umum, itu adalah dataset yang cukup bagus. Mari kita lihat korelasi antara variabel independen.


 def show_correlation(df): sns.set(style="whitegrid") corr = df.corr() * 100 # Select upper triangle of correlation matrix mask = np.zeros_like(corr, dtype=np.bool) mask[np.triu_indices_from(mask)] = True # Set up the matplotlib figure f, ax = plt.subplots(figsize=(15, 11)) # Generate a custom diverging colormap cmap = sns.diverging_palette(220, 10) # Draw the heatmap with the mask and correct aspect ratio sns.heatmap(corr, mask=mask, cmap=cmap, center=0, linewidths=1, cbar_kws={"shrink": .7}, annot=True, fmt=".2f") plot.show() # df[columns] = scale(df[columns]) return df df1 = show_correlation(df.drop(columns=['cost'])) 

gambar


Erm ... itu menjadi sangat menarik.
Korelasi positif
Total area - balkon . Kenapa tidak Jika flat kami besar, akan ada balkon.
Korelasi negatif
Total area - umur . Semakin baru flat, semakin besar area untuk hidup. Terdengar logis, flat baru lebih luas daripada flat lama.
Umur - balkon . Semakin tua flat semakin sedikit balkon yang dimilikinya. Tampak seperti korelasi melalui variabel lain. Mungkin itu adalah segitiga Umur-Balkon-Area di mana satu variabel memiliki pengaruh implisit pada variabel lain. Tunggu sebentar.
Umur - distrik. Flat yang lebih tua adalah probabilitas besar yang akan ditempatkan di distrik yang lebih bergengsi. Mungkinkah itu terkait dengan harga yang lebih tinggi di dekat pusat?


Juga, kita bisa melihat korelasi dengan variabel dependen


 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") 

gambar


Ini dia ...


Korelasi yang sangat kuat antara bidang flat dan harga. Jika Anda ingin memiliki tempat yang lebih besar untuk hidup maka akan membutuhkan lebih banyak uang.
Ada korelasi negatif antara pasangan " umur / biaya " dan " kabupaten / biaya ". Sebuah flat di rumah baru lebih murah dari yang lama. Dan di pedesaan flat lebih murah.
Bagaimanapun, itu tampak jelas dan dapat dimengerti, jadi saya memutuskan untuk menggunakannya.


Model


Untuk tugas-tugas yang terkait dengan harga flat prediksi biasanya, gunakan regresi linier. Menurut korelasi signifikan dari tahap sebelumnya, kita bisa mencoba menggunakannya juga. Ini adalah pekerja keras yang cocok untuk banyak tugas.
Siapkan data kami untuk tindakan selanjutnya


 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) 

Kami juga membuat beberapa fungsi sederhana untuk prediksi dan evaluasi hasil. Mari lakukan percobaan pertama kami untuk memperkirakan harga!


 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) 

gambar


Yah ... akurasi 76,67%. Apakah jumlahnya banyak atau tidak? Menurut sudut pandang saya, itu tidak buruk. Selain itu, ini adalah titik awal yang baik. Tentu saja, itu tidak ideal, dan ada potensi untuk perbaikan.


Pada saat yang sama - kami mencoba memprediksi hanya satu bagian dari data. Bagaimana dengan menerapkan strategi yang sama untuk data lain? Ya, waktu untuk validasi silang.


 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) 

gambar


Hasil validasi silang. Sekarang kita ambil hasil lain. 73 kurang dari 76. Tapi, itu juga kandidat yang baik sampai saat ketika kita akan memiliki yang lebih baik. Juga, itu berarti bahwa regresi linier bekerja cukup stabil pada dataset kami.


Dan sekarang adalah waktu untuk langkah terakhir.


Kami akan melihat fitur terbaik dari regresi linier - interpretabilitas .
Keluarga model ini, berlawanan dengan model yang lebih kompleks, memiliki kemampuan pemahaman yang lebih baik. Hanya ada beberapa angka dengan koefisien dan Anda dapat memasukkan angka-angka Anda dalam persamaan, membuat matematika sederhana dan mendapatkan hasilnya.


Mari kita coba menafsirkan model kita


 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) 

Koefisien model kami


Gambarnya terlihat cukup logis. Balkon / Dinding / Area / Perbaikan memberikan kontribusi positif pada harga datar.
Flat lebih lanjut adalah semakin besar kontribusi negatif . Juga berlaku untuk usia. Flat yang lebih tua adalah harga yang lebih rendah.


Jadi, itu adalah perjalanan yang menakjubkan.
Kami mulai dari awal, menggunakan pendekatan tidak tipikal untuk transformasi data berdasarkan sudut pandang manusia (angka bukan variabel dummy), memeriksa variabel dan hubungannya satu sama lain. Setelah itu, kami membangun model sederhana kami, menggunakan validasi silang untuk menguji modelnya. Dan sebagai ceri pada kue - melihat model internal, apa yang memberi kita kepercayaan diri tentang cara kita.


Tapi! Itu bukan menyelesaikan perjalanan kita tetapi hanya istirahat. Kami akan mencoba mengubah model kami di masa depan dan mungkin (mungkin saja) itu meningkatkan akurasi prediksi.


Terima kasih sudah membaca!


Bagian kedua ada di sana

PS Sumber data dan Ipython-notebook terletak di sana

Source: https://habr.com/ru/post/id468053/


All Articles