Clustering dan Klasifikasi Big Text Data dengan Java Machine Learning. Artikel # 2 - Algoritma

gambar



Halo, Habr! Hari ini kita akan melanjutkan topik Pengelompokan dan klasifikasi data teks besar menggunakan pembelajaran mesin di Java. Artikel ini merupakan lanjutan dari artikel pertama .





Artikel tersebut akan berisi Teori, dan implementasi dari algoritma yang saya gunakan.





1.



:



โ€’ . (, ). , , , , , , . . . (), . โ€’ ; , . , - . , , . , , .



, . .



, ยซยป. (, , , ), , . , , . , .



, PDF-, , , . , . .



. , , , , . , , , , , . , . . . , , , . , .



, , . , , . , . . , , , , , , . , , . , . , .





:



Iterator<String> finalIterator = new WordIterator(reader);


private final BufferedReader br;
String curLine;
public WordIterator(BufferedReader br) {
        this.br = br;
        curLine = null;
        advance();
    }
    private void advance() {
        try {
            while (true) {
                if (curLine == null || !matcher.find()) {
                    String line = br.readLine();
                    if (line == null) {
                        next = null;
                        br.close();
                        return;
                    }
                    matcher = notWhiteSpace.matcher(line);
                    curLine = line;
                    if (!matcher.find())
                        continue;                    
                }
                next = curLine.substring(matcher.start(), matcher.end());
                break;
            }
        } catch (IOException ioe) {
            throw new IOError(ioe);
        }
    }


2. -



:



, , ยซ-ยป, ยซ-ยป. , . - . -. - 1958 .. . - โ€’ , , . , , , , , , , , , , , , , , , , , , , , , . . , . - , , , . , ยซ ยป, -, โ€œโ€, โ€œโ€, โ€œ โ€, โ€œโ€. , ยซโ€ โ€œโ€, , , โ€œโ€ โ€žโ€œ . , , , : โ€œโ€, โ€œ โ€, โ€œโ€, , . , . - , , .



. -, . , ยป ", ยซยป, ยซยป, . -, , , , . , . .

- :



  • - โ€’ .
  • , -, , , , -.
  • - - . .
  • , .
  • , -, , .
  • - .
  • - :
  • : -, -. .
  • , (ยซโ€”ยป): - -. (TF-High), , , . . (TF1), (IDF).
  • (MI): , (, , ), , . , , .


Term Random Sampling (TBRS): Sebuah metode di mana kata-kata berhenti dideteksi secara manual dari dokumen. Metode ini digunakan dengan mengulangi potongan data individual yang dipilih secara acak dan memberi peringkat fitur di setiap potongan berdasarkan nilainya dalam format menggunakan ukuran divergensi Kullback-Leibler, seperti yang ditunjukkan pada persamaan berikut:



d_x (t) = Px (t) .log_2โก ใ€–( Px (t)) โ„ (P (t))ใ€— di



mana Px (t) adalah frekuensi ternormalisasi dari istilah t dalam bobot x

P (t) adalah frekuensi ternormalisasi dari istilah t di seluruh kumpulan.

Daftar perhentian terakhir dibuat dengan menerima istilah yang paling tidak informatif di semua dokumen, menghapus semua kemungkinan duplikat.





Kode:

TokenFilter filter = new TokenFilter().loadFromResource("stopwords.txt")
if (!filter.accept(token)) continue;


private Set<String> tokens;
private boolean excludeTokens;
private TokenFilter parent;

public TokenFilter loadFromResource(String fileName) {
		try {
			ClassLoader classLoader = getClass().getClassLoader();
			String str = IOUtils.toString(
					classLoader.getResourceAsStream(fileName),
					Charset.defaultCharset());
			InputStream is = new ByteArrayInputStream(str.getBytes());
			BufferedReader br = new BufferedReader(new InputStreamReader(is));

			Set<String> words = new HashSet<String>();
			for (String line = null; (line = br.readLine()) != null;)
				words.add(line);
			br.close();

			this.tokens = words;
			this.excludeTokens = true;
			this.parent = null;
		} catch (Exception e) {
			throw new IOError(e);
		}
		return this;
	}
public boolean accept(String token) {
		token = token.toLowerCase().replaceAll("[\\. \\d]", "");
		return (parent == null || parent.accept(token))
				&& tokens.contains(token) ^ excludeTokens && token.length() > 2 && token.matches("^[-]+");
	}


Mengajukan:



















....


3. Lemmatisasi



Teori:



. , . , .



โ€’ , , . , . , , ( ). , working, works, work work, : work; , . . , computers, computing, computer , : compute, . , , . , - , , , . , , .



Selama bertahun-tahun, sejumlah alat telah dikembangkan yang menyediakan fungsionalitas lemmatisasi. Meskipun metode pemrosesan yang digunakan berbeda, mereka semua menggunakan leksikon kata, seperangkat aturan, atau kombinasi dari semuanya sebagai sumber untuk analisis morfologi. Alat lemmatisasi yang paling terkenal adalah:



  • WordNet โ€’ WordNet . , , , , . , . WordNet . .
  • CLEAR โ€’ . WordNet , . NLP, , .
  • GENIA POS , . POS, . : , , . WordNet, , , GENIA PennBioIE. , . , .
  • TreeTagger POS. , , TreeTagger , . GENIA TreeTagger , POS .
  • Norm LuiNorm , . , , . UMLS, , , -, . . , . POS .
  • MorphAdorner โ€“ , , , POS . , MorphAdorner , . , .
  • morpha โ€“ . 1400 , , , , . , WordNet, 5 000 6 000 . morpha , .


:



Properties props = new Properties();
props.setProperty("annotators", "tokenize, ssplit, pos, lemma");
StanfordCoreNLP pipeline = new StanfordCoreNLP(props);
String token = documentTokens.next().replaceAll("[^a-zA-Z]", "").toLowerCase();
         Annotation lemmaText = new Annotation(token);
         pipeline.annotate(lemmaText);
         List<CoreLabel> lemmaToken = lemmaText.get(TokensAnnotation.class);
         String word = "";
         for(CoreLabel t:lemmaToken) {
           word = t.get(LemmaAnnotation.class);  //   (  )
         }


4. โ€“



:



Term Frequency - Inverse Document Frequency (TF-IDF) adalah algoritma yang paling banyak digunakan untuk menghitung bobot istilah (kata kunci dalam dokumen) dalam sistem temu kembali informasi modern. Bobot ini adalah ukuran statistik yang digunakan untuk menilai seberapa penting sebuah kata bagi dokumen dalam serangkaian dokumen atau dalam korpus. Nilainya meningkat secara proporsional dengan berapa kali kata tersebut muncul dalam dokumen, tetapi mengkompensasi frekuensi kata dalam korpus

...

(TF), , , , () . . (), , , . , . TF โ€“ . t D:



tf(t,D)=f_(t,D),



f_(t,D) โ€“ .

:

ยซยป: tf(t,D) = 1, t D 0 ;

, :



tf(t,D)=f_(t,D)โ„(โˆ‘_(t^'โˆˆD)โ–’f_(t^',D) )



:



logโกใ€–(1+f_(t,D))ใ€—



, , , :



tf(t,D)=0.5+0.5*f_(t,D)/(maxโก{f_(t^',D):t'โˆˆD})



IDF, , , , . , , . , , , , :



idf(t,D)=logโกN/|{dโˆˆD:tโˆˆd}|



TF IDF, TF-IDF, . , , . TF-IDF . TF-IDF : :



tfidf(t,D)=tf(t,D)*idf(t,D)





:

private final TObjectIntMap<T> counts;
public int count(T obj) {
    int count = counts.get(obj);
    count++;
    counts.put(obj, count);
    sum++;
    return count;
}


public synchronized int addColumn(SparseArray<? extends Number> column) {
     if (column.length() > numRows)
         numRows = column.length();
    
     int[] nonZero = column.getElementIndices();
     nonZeroValues += nonZero.length;
     try {
         matrixDos.writeInt(nonZero.length);
         for (int i : nonZero) {
             matrixDos.writeInt(i); // write the row index
             matrixDos.writeFloat(column.get(i).floatValue());
         }
     } catch (IOException ioe) {
         throw new IOError(ioe);
     }
     return ++curCol;
}


public interface SparseArray<T> {
    int cardinality();
    T get(int index);
    int[] getElementIndices();
    int length();
    void set(int index, T obj);
    <E> E[] toArray(E[] array);
}


public File transform(File inputFile, File outFile, GlobalTransform transform) {
     try {
         DataInputStream dis = new DataInputStream(
             new BufferedInputStream(new FileInputStream(inputFile)));
         int rows = dis.readInt();
         int cols = dis.readInt();
         DataOutputStream dos = new DataOutputStream(
             new BufferedOutputStream(new FileOutputStream(outFile)));
         dos.writeInt(rows);
         dos.writeInt(cols);
         for (int row = 0; row < rows; ++row) {
             for (int col = 0; col < cols; ++col) {
                 double val = dis.readFloat();
                 dos.writeFloat((float) transform.transform(row, col, val));
             }
         }
         dos.close();
         return outFile;
     } catch (IOException ioe) {
         throw new IOError(ioe);
     }
}

public double transform(int row, int column, double value) {
        double tf = value / docTermCount[column];
        double idf = Math.log(totalDocCount / (termDocCount[row] + 1));
        return tf * idf;
}


public void factorize(MatrixFile mFile, int dimensions) {
        try {
            String formatString = "";
            switch (mFile.getFormat()) {
            case SVDLIBC_DENSE_BINARY:
                formatString = " -r db ";
                break;
            case SVDLIBC_DENSE_TEXT:
                formatString = " -r dt ";
                break;
            case SVDLIBC_SPARSE_BINARY:
                formatString = " -r sb ";
                break;
            case SVDLIBC_SPARSE_TEXT:
                break;
            default:
                throw new UnsupportedOperationException(
                    "Format type is not accepted");
            }

            File outputMatrixFile = File.createTempFile("svdlibc", ".dat");
            outputMatrixFile.deleteOnExit();
            String outputMatrixPrefix = outputMatrixFile.getAbsolutePath();

            LOG.fine("creating SVDLIBC factor matrices at: " + 
                              outputMatrixPrefix);
            String commandLine = "svd -o " + outputMatrixPrefix + formatString +
                " -w dt " + 
                " -d " + dimensions + " " + mFile.getFile().getAbsolutePath();
            LOG.fine(commandLine);
            Process svdlibc = Runtime.getRuntime().exec(commandLine);
            BufferedReader stdout = new BufferedReader(
                new InputStreamReader(svdlibc.getInputStream()));
            BufferedReader stderr = new BufferedReader(
                new InputStreamReader(svdlibc.getErrorStream()));

            StringBuilder output = new StringBuilder("SVDLIBC output:\n");
            for (String line = null; (line = stderr.readLine()) != null; ) {
                output.append(line).append("\n");
            }
            LOG.fine(output.toString());
            
            int exitStatus = svdlibc.waitFor();
            LOG.fine("svdlibc exit status: " + exitStatus);

            if (exitStatus == 0) {
                File Ut = new File(outputMatrixPrefix + "-Ut");
                File S  = new File(outputMatrixPrefix + "-S");
                File Vt = new File(outputMatrixPrefix + "-Vt");
                U = MatrixIO.readMatrix(
                        Ut, Format.SVDLIBC_DENSE_TEXT, 
                        Type.DENSE_IN_MEMORY, true); //  U
                scaledDataClasses = false; 
                
                V = MatrixIO.readMatrix(
                        Vt, Format.SVDLIBC_DENSE_TEXT,
                        Type.DENSE_IN_MEMORY); //  V
                scaledClassFeatures = false;


                singularValues =  readSVDLIBCsingularVector(S, dimensions);
            } else {
                StringBuilder sb = new StringBuilder();
                for (String line = null; (line = stderr.readLine()) != null; )
                    sb.append(line).append("\n");
                // warning or error?
                LOG.warning("svdlibc exited with error status.  " + 
                               "stderr:\n" + sb.toString());
            }
        } catch (IOException ioe) {
            LOG.log(Level.SEVERE, "SVDLIBC", ioe);
        } catch (InterruptedException ie) {
            LOG.log(Level.SEVERE, "SVDLIBC", ie);
        }
    }

    public MatrixBuilder getBuilder() {
        return new SvdlibcSparseBinaryMatrixBuilder();
    }

    private static double[] readSVDLIBCsingularVector(File sigmaMatrixFile,
                                                      int dimensions)
            throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(sigmaMatrixFile));
        double[] m = new double[dimensions];

        int readDimensions = Integer.parseInt(br.readLine());
        if (readDimensions != dimensions)
            throw new RuntimeException(
                    "SVDLIBC generated the incorrect number of " +
                    "dimensions: " + readDimensions + " versus " + dimensions);

        int i = 0;
        for (String line = null; (line = br.readLine()) != null; )
            m[i++] = Double.parseDouble(line);
        return m;
    }


SVD Java ( S-space)



5. Aylien API



Aylien API Text Analysis โ€’ API .

Aylien API , , , . โ€’ .



, IPTC, -, โ€’ IAB-QAG, .



Taksonomi kontekstual IAB-QAG dikembangkan oleh IAB (Interactive Advertising Bureau) bersama dengan pakar taksonomi dari akademisi untuk menentukan kategori konten setidaknya dua tingkat yang berbeda, membuat klasifikasi konten jauh lebih konsisten. Tingkat pertama adalah kategori tingkat yang luas, dan yang kedua adalah deskripsi yang lebih rinci tentang struktur tipe akar (Gambar 6).

Untuk menggunakan API ini, Anda perlu mendapatkan kunci dan ID di situs web resmi. Kemudian, dengan menggunakan data ini, Anda dapat menggunakan kode Java untuk memanggil metode POST dan GET.



private static TextAPIClient client = new TextAPIClient(" ", " ")


Anda kemudian dapat menggunakan klasifikasi dengan meneruskan data yang akan diklasifikasikan.



ClassifyByTaxonomyParams.Builder builder = ClassifyByTaxonomyParams.newBuilder();
URL url = new URL("http://techcrunch.com/2015/07/16/microsoft-will-never-give-up-on-mobile");
builder.setUrl(url);
builder.setTaxonomy(ClassifyByTaxonomyParams.StandardTaxonomy.IAB_QAG);
TaxonomyClassifications response = client.classifyByTaxonomy(builder.build());
for (TaxonomyCategory c: response.getCategories()) {
  System.out.println(c);
}


Tanggapan dari layanan dikembalikan dalam format json:



{
  "categories": [
    {
      "confident": true,
      "id": "IAB19-36",
      "label": "Windows",
      "links": [
        {
          "link": "https://api.aylien.com/api/v1/classify/taxonomy/iab-qag/IAB19-36",
          "rel": "self"
        },
        {
          "link": "https://api.aylien.com/api/v1/classify/taxonomy/iab-qag/IAB19",
          "rel": "parent"
        }
      ],
      "score": 0.5675236066291172
    },
    {
      "confident": true,
      "id": "IAB19",
      "label": "Technology & Computing",
      "links": [
        {
          "link": "https://api.aylien.com/api/v1/classify/taxonomy/iab-qag/IAB19",
          "rel": "self"
        }
      ],
      "score": 0.46704140928338533
    }
  ],
  "language": "en",
  "taxonomy": "iab-qag",
  "text": "When Microsoft announced its wrenching..."
}


API ini digunakan untuk mengklasifikasikan cluster yang akan diperoleh dengan menggunakan metode clustering pembelajaran unsupervised.



Kata Penutup



Saat menerapkan algoritma yang dijelaskan di atas, ada alternatif dan pustaka yang sudah jadi. Anda hanya perlu melihat. Jika Anda menyukai artikel tersebut, atau memiliki ide atau pertanyaan, silakan tinggalkan komentar Anda. Bagian ketiga akan menjadi abstrak, terutama membahas arsitektur sistem. Deskripsi algoritme, apa yang digunakan dan dalam urutan apa.



Selain itu, akan ada hasil masing-masing setelah penerapan algoritma masing-masing, serta hasil akhir dari pekerjaan ini.




All Articles