Việc triển khai Spark cĩ hai giai đoạn:
Giai đoạn 1: Xây dựng trình phân loại Nạve Bayes bằng dữ liệu training để thực hiện điều này sử dụng lớp BuildNạveBayesClassifier. Lớp này đọc dữ liệu huấn luyện và xây dựng trình phân loại Nạve Bayes. Đặt C = {C1, C2, ..., Ck} là một tập hợp các phân loại và dữ liệu đào tạo đƣợc xác định nhƣ sau:
Đặt X = {X1, X2, ..., Xn} là dữ liệu thơ.
Mỗi Xi cĩ m thuộc tính và đƣợc phân loại là: X1 = {X11, X12, ..., X1m} → c1∊ C
X2 = {X21, X22, ..., X2m} → c2∊ C ...
Xn = {Xn1, Xn2, ..., Xnm} → cn∊ C
Mục tiêu của Tơi là tạo ra các hàm bảng xác suất (Xác suất) sau đây: Xác suất (Ci) = pValue
Xác suất (Aj, Ci) = pValue
Trong đĩ Aj là một thuộc tính của X và 0,00 ≤ pValue ≤ 1,00.[5]
Giai đoạn 2: Sử dụng Nạve Bayes Classifier mới đƣợc xây dựng để
phân loại dữ liệu mới
Khi đã xây dựng trình phân loại Nạve Bayes, sẽ sử dụng các hàm ProbabilityTable () để phân loại dữ liệu mới. Thực hiện điều này bằng cách sử dụng lớp sifier NaiveBayesClass. Lớp này đọc trình phân loại (đƣợc biểu thị
42
dƣới dạng các hàm Bleability ()) dữ liệu mới bằng cách sử dụng dữ liệu cĩ sẵn [5].
Hình 2.9 Giai đoạn phân loại [5].
Giai đoạn 1: Xây dựng Trình phân loại bằng Dữ liệu training
Giai đoạn này đƣợc thực hiện bởi lớp Build Nạve Bayes Classifier, chấp nhận dữ liệu đào tạo (đã đƣợc phân loại) và xây dựng trình phân loại Nạve Bayes. Trình phân loại Nạve Bayes là một tập hợp các bảng xác suất (PT). Đầu tiên, Ví dụ 2.1 trình bày lớp Build NaiveBayes Classifierdƣới dạng tập hợp các bƣớc cấp cao, sau đĩ tơi sẽ giải thích chi tiết từng bƣớc.[11]
Ví dụ 2.1. Xây dựng bộ phân loại.
Bƣớc 1: Thêm vào các thƣ viện lớp và giao diện Bƣớc 2: Xử lý thơng số đầu vào
Bƣớc 3: Tạo một đối tƣợng mới trên Spark. Bƣớc 4: Đọc dữ liệu huấn luyện
Bƣớc 5: Tiến hành thực hiện hàm map () cho tất cả các biến của dữ liệu huấn luyện.
43
Bƣớc 6: Tiến hành thực hiện hàm reduce () cho tất cả các biến của dữ liệu huấn luyện.
Bƣớc 7: Tiến hành reduce dữ liệu từ Map Bƣớc 8: Xây dựng trình phân loại
Bƣớc 9: Lƣu trữ trình phân loại
Phƣơng thức toWritableList (), đƣợc định nghĩa trong Ví dụ 2.2, chuẩn bị bộ phân loại sẽ đƣợc lƣu trong HDFS. Để hoạt động đƣợc, dữ liệu đầu vào sẽ sử dụng phƣơng thức Writablecủa Hadoop để lƣu bộ phân loại vào HDFS
Ví dụ 2.2: phƣơng thức toWritableList ()
static List<Tuple2<PairOfStrings, DoubleWritable>> toWritableList(Map<Tuple2<String,String>, Double> PT) {
List<Tuple2<PairOfStrings, DoubleWritable>> list = new ArrayList<Tuple2<PairOfStrings, DoubleWritable>();
for (Map.Entry<Tuple2<String,String>, Double> entry : PT.entrySet()) {
list.add(new Tuple2<PairOfStrings, DoubleWritable>( new PairOfStrings(entry.getKey()._1, entry.getKey()._2), new DoubleWritable(entry.getValue())
}
return list; }
Bước 1: Nhập các lớp và giao diện pyspark cần thiết (Ví dụ 2.3).
Ví dụ 2.3. Bƣớc 1: nhập các lớp và giao diện cần thiết
import java.util.Map; import java.util.HashMap; import java.util.List;
44 import java.util.ArrayList; import scala.Tuple2; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaPairRDD; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.api.java.function.PairFunction; import org.apache.spark.api.java.function.PairFlatMapFunction; import org.apache.spark.api.java.function.FlatMapFunction; import org.apache.spark.api.java.function.Function; import org.apache.spark.api.java.function.Function2; import org.apache.spark.broadcast.Broadcast; import edu.umd.cloud9.io.pair.PairOfStrings; import org.apache.hadoop.mapred.SequenceFileOutputFormat; import org.apache.hadoop.io.DoubleWritable;
Bước 2: Xử lý các tham số đầu vào
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.4, đọc một tham số đầu vào, <tên tập tin dữ liệu>, là tệp HDFS đại diện cho dữ liệu đào tạo đƣợc sử dụng để xây dựng trình phân loại Nạve Bayes.
Ví dụ 2.4. Bƣớc 2: xử lý các tham số đầu vào
if (args.length < 1) {
System.err.println("Usage: BuildNaiveBayesClassifier <training-data-filename>");
System.exit(1); }
final String trainingDataFilename = args[0];
45
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.5, tạo một đối tƣợng SparkContext và khởi tạo RDD mới. Lớp SparkUtil cĩ các phƣơng thức tĩnh đƣợc tạo tức thì, các trƣờng hợp của pySparkContext sử dụng trình quản lý tài nguyên của YARN hoặc bằng cách sử dụng URL chính Spark.
Ví dụ 2.5. Bƣớc 3: tạo một đối tƣợng bối cảnh Spark
JavaSparkContext ctx = SparkUtil.createJavaSparkContext("naive- bayes");
Bước 4: Đọc dữ liệu đào tạo
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.6, sử dụng một thể hiện của JavaSparkContext để đọc dữ liệu đào tạo của chúng tơi và tạo một JavaRDD <String>, trong đĩ mỗi phần tử là một bản ghi của tập dữ liệu huấn luyện theo định dạng sau:
<attribute_1><,><attribute_2><,>...<,><attribute_m><,><classification Ví dụ 2.6. Bƣớc 4: đọc dữ liệu đào tạo
JavaRDD<String> training = ctx.textFile(trainingDataFilename, 1); training.saveAsTextFile("/output/1");
long trainingDataSize = training.count();
Bước 5: Thực hiện chức năng map () cho tất cả các yếu tố của dữ liệu đào tạo
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.7, ánh xạ tất cả các yếu tố của dữ liệu đào tạo để cĩ thể tạo ra một số lƣợng các thuộc tính liên quan đến phân loại. Sau đĩ, sử dụng các số đếm này để tính xác suất cĩ điều kiện.
Ví dụ 2.7. Bƣớc 5: thực hiện hàm map ()
JavaPairRDD<Tuple2<String,String>,Integer> pairs = training.flatMapToPair(new PairFlatMapFunction< String, Tuple2<String,String>,Integer
46
public Iterable<Tuple2<Tuple2<String,String>,Integer>> call(String
rec) {
List<Tuple2<Tuple2<String,String>,Integer>> result =
new ArrayList<Tuple2<Tuple2<String,String>,Integer>>();
String[] tokens = rec.split(",");
int classificationIndex = tokens.length -1;
String theClassification = tokens[classificationIndex];
for(int i=0; i < (classificationIndex-1); i++) {
Tuple2<String,String> K = new Tuple2<String,String>("CLASS", theClassification); result.add(new Tuple2<Tuple2<String,String>,Integer>(K, 1)); return resultt; } }); pairs.saveAsTextFile("/output/2");
Bước 6: Thực hiện hàm less()
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.8, làm giảm số lƣợng để chuẩn bị tính tốn các xác suất cĩ điều kiện sẽ đƣợc phân loại sử dụng.
Ví dụ 2.8. Bƣớc 6: thực hiện hàm less ()
JavaPairRDD<Tuple2<String,String>, Integer> counts =
pairs.reduceByKey(new Function2<Integer, Integer, Integer>() {
public Integer call(Integer i1, Integer i2) { return i1 + i2;
} });
counts.saveAsTextFile("/output/3");
47
Nhƣ đã trình bày trong Ví dụ 2.9, bƣớc này sử dụng một tính năng mạnh mẽ của API Spark là nhĩm một JavaPairRDD <K,V> nhƣ một Map <K,V> . Tơi sẽ sử dụng Map <K,V> đƣợc tạo để xây dựng trình phân loại.
Ví dụ 2.9. Bƣớc 7: Tiến hành reduce dữ liệu từ hàm Map Map<Tuple2<String,String>, Integer> countsAsMap = counts.collectAsMap();
Bước 8: Xây dựng cấu trúc dữ liệu phân loại
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.10, xây dựng trình phân loại, bao gồm:
Bảng xác suất (PT)
Danh sách phân loại (PHÂN LOẠI)
Ví dụ 2.10. Bƣớc 8: xây dựng cấu trúc dữ liệu phân loại Map<Tuple2<String,String>, Double> PT = new
HashMap<Tuple2<String,String>,Double>();
List<String> CLASSIFICATIONS = new ArrayList<String>();
for (Map.Entry<Tuple2<String,String>, Integer> entry :
countsAsMap.entrySet()) {
Tuple2<String,String> k = entry.getKey(); String classification = k._2;
if (k._1.equals("CLASS")) {
PT.put(k, ((double) entry.getValue())/ ((double) trainingDatasize)); CLASSIFICATION.add(k._2); } else{ Tuple2<String,String>k2=new Tuple2<String,String>("CLASS",classification);
48 Integer count = countsAsMap.get(k2); If (count == null){ PT.put(k, 0.0); } else { PT.put(k,((double)entry.getValue())/ ((double) count.intValue()));}}} System.out.println("PT="+PT);
Bước 9: Lưu cấu trúc dữ liệu phân loại
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.11, lƣu bộ phân loại, bao gồm: Bảng xác suất (PT)
Danh sách phân loại (PHÂN LOẠI)
Để lƣu bất kỳ dữ liệu nào trong Hadoop, lớp dữ liệu đƣợc duy trì của bạn phải triển khai trên Hadoop
Giao diện org.apache.hadoop.io.Writable 1. Trong đoạn mã, tơi đã sử dụng PairOfStrings và DoubleWritable cho các lớp, mà cả hai thực hiện trên giao diện Writable của Hadoop.
Ví dụ 2.11. Bƣớc 9: Lƣu cấu trúc dữ liệu phân loại
// Bước 9.1: Lưu lại PT
List<Tuple2<PairOfStrings, DoubleWritable>> list = toWritableList(PT); JavaPairRDD<PairOfStrings, DoubleWritable> ptRDD = ctx.parallelizePairs(list); ptRDD.saveAsHadoopFile("/naivebayes/pt", PairOfStrings.class, DoubleWritable.class, SequenceFileOutputFormat.class
49 );
// Bước 9.2: Lưu danh sách phân loại
JavaRDD<String> classificationsRDD = ctx.parallelize(CLASSIFICATIONS);
classificationsRDD.saveAsTextFile("/naivebayes/classes");
Tập lệnh YARN để xây dựng một Nạve Bayes Classifier.
Kịch bản shell hiển thị ở đây chạy chƣơng trình Spark để xây dựng Nạve Bayes Classifier trong mơi trƣờng YARN:[11]
# cat run_build_naive_bayes_classifier.sh #!/bin/bash
#... set the CLASSPATH(s) accordingly... BOOK_HOME=/mp/data-algorithms-book
APP_JAR=$BOOK_HOME/dist/data_algorithms_book.jar THE_JARS=$BOOK_HOME/lib/cloud9-1.3.2.jar
INPUT=/naivebayes/training_data.txt
prog=org.dataalgorithms.chap14.spark.BuildNaiveBayesClassifier $SPARK_HOME/bin/spark-submit --class $prog
--master yarn-cluster --num-executors --driver-memory --executor-memory --executor-cores --jars $THE_JARS $APP_JAR $INPUT
Giai đoạn 2: Sử dụng Trình phân loại để phân loại dữ liệu mới.[11]
Trong giai đoạn 1, chúng tơi đã xây dựng một trình phân loại Nạve Bayes bằng cách sử dụng dữ liệu đào tạo đƣợc cung cấp. Mục tiêu của giai
50
đoạn 2 là phân loại dữ liệu mới bằng cách sử dụng trình phân loại đĩ. Trong giai đoạn 2, chúng tơi đọc trình phân loại từ HDFS và sau đĩ phân loại dữ liệu đầu vào của chúng tơi cho phù hợp. Chúng tơi sẽ sử dụng cách sau đây để phân loại dữ liệu mới của Nạve Bayes:
Cpredict=argcmaxP(C=c) ∏P(Xj= uj|C=c)
m
j=1
Việc phân loại đƣợc thực hiện bởi một lớp trình điều khiển duy nhất (Nạve Bayes Classifier) bằng API Spark. Một lần nữa, sẽ trình bày các bƣớc cấp cao (Ví dụ 2.12), sau đĩ thảo luận chi tiết từng bƣớc.
Ví dụ 2.12. Các bƣớc cấp cao cho giải pháp Spark Nạve Bayes Classifier
Bƣớc 1: Thêm thƣ viện các lớp và giao diện
public class NaiveBayesClassifier implements java.io.Serializable { public static void main(String[] args) throws Exception {
Bƣớc 2: Xử lý các tham số đầu vào
Bƣớc 3: Tạo một đối tƣợng mới trên Spark. Bƣớc 4: Đọc dữ liệu mới để phân loại Bƣớc 5: Đọc trình phân loại từ Hadoop
Bƣớc 6: Bộ nhớ đệm các thành phần trình phân loại, cĩ thể đƣợc sử dụng từ bất kỳ nút nào trong cụm.
Bƣớc 7: Phân loại dữ liệu mới Kết thúc
ctx.close(); System.exit(0); }
Bước 1: Nhập các lớp và giao diện cần thiết
Đối với bƣớc đầu tiên, đƣợc hiển thị trong Ví dụ 2.13, tiến hành nhập các lớp và giao diện cần thiết cho giải pháp này.
51
Ví dụ 2.13. Bƣớc 1: Nhập các lớp và giao diện cần thiết
import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import scala.Tuple2; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaPairRDD; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.api.java.function.PairFunction; import org.apache.spark.api.java.function.PairFlatMapFunction; import org.apache.spark.api.java.function.FlatMapFunction; import org.apache.spark.api.java.function.Function; import org.apache.spark.api.java.function.Function2; import org.apache.spark.broadcast.Broadcast; import edu.umd.cloud9.io.pair.PairOfStrings; import org.apache.hadoop.mapred.SequenceFileInputFormat; import org.apache.hadoop.io.DoubleWritable;
Bước 2: Xử lý các tham số đầu vào
Bƣớc hiển thị trong Ví dụ 2.14 xử lý các tham số đầu vào cho giải pháp Ví dụ 2.14. Bƣớc 2: xử lý các tham số đầu vào
if (args.length != 2) {
System.err.println("Usage: NaiveBayesClassifier +
<input-data-filename> <NB-PT-path>");
System.exit(1);
}
52
final String nbProbabilityTablePath = args[1];// một phần của phân
loại
Bước 3: Tạo một đối tượng bối cảnh Spark
Sử dụng lớp SparkUtil, trong ví dụ 2.15, tạo một đối tƣợng của Spark và lƣu trữ trên RDD mới.
Ví dụ 2.15. Bƣớc 3: Tạo một đối tƣợng bối cảnh Spark
JavaSparkContext ctx =
SparkUtil.createJavaSparkContext("naive-bayes");
Bước 4: Đọc dữ liệu mới để được phân loại
Dữ liệu thơ đƣợc phân loại (xem ví dụ 2.16 ) cĩ định dạng bản ghi sau: <attribute_1><,><attribute_2><,>...<,><attribute_m>
Ví dụ 2.16. Bƣớc 4: đọc dữ liệu mới để đƣợc phân loại
JavaRDD<String> newdata = ctx.textFile(inputDataFilename, 1);
Bước 5: Đọc trình phân loại từ Hadoop
Bƣớc này, thể hiện trong ví dụ 2.17, đọc các thành phần phân loại và struc dữ liệu - tures xây dựng bởi BuildNaiveBayesClassifier lớp (trong giai đoạn 1). Khi các thành phần phân loại đƣợc đọc, chúng tơi sẵn sàng phân loại dữ liệu mới.
Ví dụ 2.17. Bƣớc 5: đọc trình phân loại từ Hadoop
JavaPairRDD<PairOfStrings, DoubleWritable> ptRDD = ctx.hadoopFile( nbProbabilityTablePath, SequenceFileInputFormat.class, PairOfStrings.class, DoubleWritable.class );
53
JavaPairRDD<Tuple2<String,String>, Double> classifierRDD = ptRDD.mapToPair( new PairFunction< Tuple2<PairOfStrings,DoubleWritable>, // T Tuple2<String,String>, Double >() { public Tuple2<Tuple2<String,String>,Double> call(Tuple2<PairOfStrings,DoubleWritable> rec) { PairOfStrings pair = rec._1;
Tuple2<String,String> K2 =
Double V2 = new Double(rec._2.get());
new Tuple2<String,String>(pair.getLeftElement(), pair.getRightElement());
return new Tuple2<Tuple2<String,String>,Double>(K2, V2); }
});
Bước 6: Cache các thành phần phân loại
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.18, lƣu trữ các thành phần phân loại (sử dụng lớp Phát sĩng của Spark) để chúng cĩ thể đƣợc truy cập và sử dụng từ bất kỳ nút cụm nào.
Ví dụ 2.18. Bƣớc 6: lƣu trữ các thành phần phân loại Map<Tuple2<String,String>, Double> classifier = classifierRDD.collectAsMap();
final Broadcast<Map<Tuple2<String,String>, Double>>
broadcastClassifier =
ctx.broadcast(classifier);
JavaRDD<String> classesRDD = ctx.textFile("/naivebayes/classes", 1); List<String> CLASSES = classesRDD.collect();
54
final Broadcast<List<String>> broadcastClasses =
ctx.broadcast(CLASSEDS);
Bước 7: Phân loại dữ liệu mới
Bƣớc này, đƣợc hiển thị trong Ví dụ 2.19, sử dụng các thành phần phân loại để phân loại dữ liệu mới.
Ví dụ 2.19. Bƣớc 7: phân loại dữ liệu mới
JavaPairRDD<String,String> classified = newdata.mapToPair(new PairFunction<String, String, String>() {
public Tuple2<String,String> call(String rec) {
Map<Tuple2<String,String>, Double> CLASSIFIER = broadcastClassifier.value();
List<String> CLASSES = broadcastClasses.value(); String[] attributes = rec.split(",");
String selectedClass = null; double maxPosterior = 0.0; for (String aClass : CLASSES) {
double posterior = CLASSIFIER.get(new Tuple2<String,String>("CLASS",
aClass));
for (int i=0; i < attributes.length; i++) {
Double probability = CLASSIFIER.get(new Tuple2<String,String>( attributes[i], aClass)); if (probability == null) { posterior = 0.0; break; } else { if posterior > maxPosterior){
55 selectedClass = aClass; maxPosterior = posterior; } } }
return new Tuple2<String,String>(rec, selectedClass); }
});
classified.saveAsTextFile(“/output/classified”);