৭.৮. ডাটা প্রি-প্রসেসিং, ডাটা ক্লিনিং এবং ষষ্ঠ প্রেডিকশন

ডাটা প্রি-প্রসেসিং, ডাটা ক্লিনিং এবং ষষ্ঠ প্রেডিকশন

আমার প্রিয় চ্যাপ্টার

ডাটা নিয়ে কাজ করতে গিয়ে দেখলাম দুটো সমস্যা। ১. ডাটা’র অভাব ২. ডাটা থাকলেও সেটা পরিপূর্ণ নয়। হয় ডাটা ভুল, অথবা অনেক ডাটা মিসিং। এদিকে আগেই বলেছিলাম ডাটা না থাকা আর ডাটা’র ঘরে "শুন্য" থাকা - দুটো দু জিনিস। তবে আসল কথা হচ্ছে - ডাটা না থাকলে "প্রেডিক্ট" করবো কিভাবে?

ডাটা থাকবে না এটাই স্বাভাবিক। আশা করি একটা “পারফেক্ট ওয়ার্ল্ডে” থাকি আমরা, কিন্তু আসল কথা হচ্ছে প্রতিনিয়ত নতুন চ্যালেঞ্জ নিতে হয় আমাদের। যতই চিন্তা করি, আজকে বউ ঝগড়া করবেনা আমার সাথে, ততোই যেন ঝগড়া উড়ে উড়ে আসে। আর সেটাই স্বাভাবিক। যতোই ধারণা করি বস আমাকে বুঝবে ঠিকমতো - ততোই জিনিস উল্টোয়। এর মানে হচ্ছে - আমরা অনেক কিছুই চিন্তা করি, কিন্তু বাস্তবে হয় অন্য।

সেরকমভাবে আমরা যখন ডাটা নিয়ে কাজ করি, বেশিরভাগই সময়ে পুরো ডাটা পাইনা। আর যেটাও বা পাই় সেটাও থাকে ভুলে ভরা। মোদ্দা কথা হচ্ছে, পুরো ডাটা পাওয়া যাবে না। আর - পাওয়া গেলেও সেটা থাকবে অসম্পূর্ণ। তো অসম্পূর্ণ ডাটা থাকলে কি বসে থাকব আমরা? সেখানেই মানুষের মুনশিয়ানা। প্রতিটা ডাটা কিন্তু একে অপরের সাথে সম্পর্কযুক্ত। আমরা একে বলি “কো রিলেটেড” ডাটা।

একটা উদাহরণ টানি বরং। বাবা এবং মা’র কেবিন নাম্বারটা ডাটা সেটে থাকলেও তাদের পাঁচ বছরের সন্তানের ডাটা মিসিং। এখন সেই সন্তানের কেবিন নাম্বার কি হবে? সোজা উত্তর। বাবা আর মা’র কেবিন নাম্বারটাই হবে তাদের সন্তানের। সেটাই তো স্বাভাবিক। তাই নয় কি?

অথবা, একই পরিবারের তিন জনের জাহাজ ভাড়ার ডাটা থাকলেও আরেকজনেরটা মিসিং। তো কি হবে এখানে? ধারণার সাথে মিলিয়ে একই ভাড়ার তথ্যটা ঢুকিয়ে দেবো তার ওখানে। এছাড়াও গড় ভ্যালুটা ঢুকিয়ে দেয়া যেতে পারে সেখানে। বোঝা গেছে তো ব্যাপারটা? ফিরে যাই আমাদের ডাটা সেটে। আমরা সামনে নিয়ে আসছি ডাটা “প্রি-প্রসেসিং” নিয়ে। আমাদেরকে “ক্লিন” করতে হবে অসম্পূর্ন ডাটা। ভরতে হবে বিশ্বাসযোগ্য ডাটা দিয়ে। ডাটাকে তৈরি করতে হবে নতুন নতুন টেকনিকের জন্য ঠিক করে।

> summary(combined_set$Age)

Min. 1st Qu. Median Mean 3rd Qu. Max. NA's

0.17 21.00 28.00 29.88 39.00 80.00 263

সোজা পথ আছে একটা। আমাদের বয়স ভ্যারিয়েবলটা দেখি বরং। এখানে দেখছি “NA's” ই আছে ১৬৩টা। “NA” মানে নট এভেইল্যাবল। মানে বয়স দেয়া নেই আমাদের ২৬৩টা রেকর্ডে। মানে প্রায় ২০%! ভয়ংকর অবস্থা। কেমন হয় বাকি সব বয়সের গড় বের করে ভর্তি করি ফাঁকা রেকর্ডে? আসলেই তাই। নাই মামা থেকে কানা মামা ভালো। আর ব্যাপারটা তো মিথ্যে নয়। সবার গড় বয়স দিয়ে রিপ্লেস করে দেবো মিসিং ভ্যালুগুলো। মানে সব “NA's”গুলো।

দ্বিতীয় পন্থা আরো মজার। মনে আছে “ডিসিশন ট্রি’র কথা? “ডিসিশন ট্রি’ তো জানে অন্য ডাটার কথা। সেখান থেকে মিলিয়ে দেবে সে। কেমন হয় সেটা? কৈ এর কৈ ভাঁজা। “is.na()” এর উল্টোটা হচ্ছে “!is.na()”। মানে “NA” হওয়া যাবে না। method="anova", আমরা ক্লাসিফাই করছি না - বরং দরকার আমাদের কন্টিনিউয়াস ভ্যারিয়েবল। চলুন বাড়তে দেই আমাদের নতুন ডিসিশন ট্রি। বাকি বয়সগুলো থেকে তৈরি করি আমাদের নতুন বয়স। বিশেষ করে যেখানে বয়সের ঘর ফাঁকা। মজা না?

> FillAge <- rpart(Age ~ Pclass + Mother + FamilySize + Sex + SibSp + Parch + Deck + Fare + Embarked + Title + FamilyID + FamilySize + FamilySizeGroup, data=combined_set[!is.na(combined_set$Age),], method="anova")

ডিসিশন ট্রি’র আউটপুট নিয়ে সেটা পাঠিয়ে দিলাম প্রেডিক্ট ফাংশনে। এরপর সেটাকে ভর্তি করতে বললাম যেখানে কোন ভ্যালু নেই।

> combined_set$Age[is.na(combined_set$Age)] <- predict(FillAge, combined_set[is.na(combined_set$Age),])

আবার সামারি কমান্ড দিয়ে দেখলে দেখবেন সব ফকফকা। মানে, সব “NA” গায়েব। সেখানে এসে ঢুকে গেছে নতুন প্রেডিক্টেড ভ্যালু। খুব স্মার্ট না?

> summary(combined_set$Age)

Min. 1st Qu. Median Mean 3rd Qu. Max.

0.17 22.00 28.86 29.70 36.50 80.00

এখন দেখি, পুরো ডাটাসেটের কি অবস্থা?

> summary(combined_set)

আমাদের হাতে Embarked আর Fare ভ্যারিয়েবলগুলোর কিছু ঘর ফাঁকা আছে। দেখি তাহলে ভেতরে কি অবস্থা।

> summary(combined_set$Embarked)

C Q S
2 270 123 914

মনে আছে তো আগের ঘটনা?

embarked ----> কোথা থেকে উঠেছেন, বিশেষ করে কোন পোর্ট থেকে ------> C = Cherbourg, Q = Queenstown, S = Southampton

বোঝা যাচ্ছে দুটো প্যাসেঞ্জারের ঘর ফাঁকা আছে। এখানে একটা কথা না বললেই নয়। "NA" আর "ব্ল্যাংক" ঘরের মধ্যে পার্থক্য আছে। এখানে $Embarked ঘরটা আসলে ফাঁকা। ব্ল্যাংক। "NA" নয়। যাই হোক ক্লিন করতে বসে ঘোমটা দিয়ে থাকলে তো আর হবে না। ফেলে দেই দুটো ঘরকে। কোন দুটো ঘর তাহলে?

>which(combined_set$Embarked == '')

[1] 62 830 -------> দুটো ঘরে। আমাদের আগের হিসেবে দেখা গেছে S = Southampton থেকে মানুষ উঠেছেন বেশি।

combined_set$Embarked[c(62,830)] = "S" ------> তাহলে S = Southampton দিয়েই ভর্তি করি ফাঁকা ঘরটা।

combined_set$Embarked <- factor(combined_set$Embarked) --------> পাল্টে নিয়ে আসি আমাদের ফ্যাক্টরে।

$Fare এর মধ্যে একটা মাত্র "NA" আছে। আমাদের কষ্ট কমে গেল।

> summary(combined_set$Fare)

Min. 1st Qu. Median Mean 3rd Qu. Max. NA's

0.000 7.896 14.454 33.295 31.275 512.329 1

তো "NA"টা আছে কোথায়?

> which(is.na(combined_set$Fare))

[1] 1044 ------> ১০৪৪ এর ঘরে।

আমাদের সব প্যাসেঞ্জারদের ভাড়ার "গড়" ভ্যালুটা পাঠিয়ে দেই ওই ঘরে।

>combined_set$Fare[1044] <- median(combined_set$Fare, na.rm=TRUE)

চেক করার পালা। আগেই বলেছি - আমাদের পরের প্রেডিকশনে এমন টেকনিক ব্যবহার করছি যা কোন ধরণের ব্ল্যাংক বা "NA" ভ্যালু নিতে পারে না।

লোড করে নেই আমাদের mice প্যাকেজ।

library('mice')

library('lattice')

এরপর কমান্ড দেই প্যাটার্নের। কোন মিসিং ভ্যালু নেই আর। অল সেট আমরা!

>md.pattern(combined_set)ছবি: কোন মিসিং ভ্যালু নেই এখানে

আমাদের কাজ প্রায় শেষ। এখন একটা প্রেডিকশনের পালা। করবেন কি আপনি? পুরানো ডিসিশন ট্রি দিয়েই তবে নতুন "মিসিং ডাটা" ছাড়া ডাটা দিয়ে। আগে যা করেছি সেখানে অনেক ডাটা "মিসিং" ছিলো। গিটহাবের স্ক্রিপ্টটা দেখবেন ভালো করে। আসল ঘটনা ওই স্ক্রিপ্টে। সত্যি বলছি। অনেক কারুকাজ আছে ওখানে।

ব্যবহৃত গিটহাব স্ক্রিপ্ট (অনলাইন)

https://github.com/raqueeb/mltraining/blob/master/ML-workbook/6th-prediction.R

কি হলো? খুব একটা এগুতে পারিনি আমরা লিডারবোর্ডে। কেন? ডাটা তো সব ভর্তি। কি হলো তাহলে? সব ভ্যারিয়েবল কি নেয়া ঠিক হয়েছে?