2013-03-25 13 views
11

私はjavaに慣れていないし、単純なNaiveBayesクラシファイアを作成して練習しています。私はまだオブジェクトのインスタンス化には新しく、HashMapのHashMapを初期化するために何をすべきか考えています。新しい観測値をクラシファイアに挿入する際、特定のクラスで見えないフィーチャ名に対して新しいHashMapを作成できますが、初期化する必要はありますか?この質問は、ナイーブベイズ分類器に固有ではないJava - HashMapsのHashMapを初期化する

import java.util.HashMap; 

public class NaiveBayes { 

    private HashMap<String, Integer> class_counts; 
    private HashMap<String, HashMap<String, Integer>> class_feature_counts; 

    public NaiveBayes() { 
     class_counts = new HashMap<String, Integer>(); 
     // do I need to initialize class_feature_counts? 
    } 

    public void insert() { 
     // todo 
     // I think I can create new hashmaps on the fly here for class_feature_counts 
    } 

    public String classify() { 
     // stub 
     return ""; 
    } 

    // Naive Scoring: 
    // p(c | f_1, ... f_n) =~ p(c) * p(f_1|c) ... * p(f_n|c) 
    private double get_score(String category, HashMap features) { 
     // stub 
     return 0.0; 
    } 

    public static void main(String[] args) { 
     NaiveBayes bayes = new NaiveBayes(); 
     // todo 
    } 
} 

注、私はいくつかのコンテキストを提供するだろうと思いました。

+1

「_...初期化する必要がありますか?」「はい」**。 – jlordo

+3

そして、HashMapsのHashMapは通常、オブジェクトとカプセル化がないというサインです。 –

+0

クール、私はそれを感謝することができます。助言がありますか?私がこれについて考えてきたやり方は、2段階のハッシュを持つことです。たとえば、これがスパム検出であれば、{spam:{"銀行口座":3、 "viagra":9} 'あなたの考えは? ? –

答えて

18

はい、初期化する必要があります。あなたはclass_feature_countsに値を追加したい場合は

class_feature_counts = new HashMap<String, HashMap<String, Integer>>(); 

、あなたもそれをインスタンス化する必要があります。

HashMap<String, Integer> val = new HashMap<String, Integer>(); 
// Do what you want to do with val 
class_feature_counts.put("myKey", val); 
+1

こんにちは@BobTheBuilder、私はこの点の後に何をすべきかに関する質問があります。上記の例で、私は、 "MyKey"キーの下にあるclass_feature_countsに格納されているHashMap を検索していたとします。私は 'class_feature_count.get(" MyKey ")'を実行します。ただし、 "Object"オブジェクトを返します。 "HashMap"オブジェクトは返しません。そのObjectオブジェクトをHashMapにキャストするにはどうすればよいですか?ありがとう。 –

+1

実際のコードを掲載することはできますか? – BobTheBuilder

+1

こんにちは@BobTheBuilder、ここに行く:https://pastebin.com/pJG49LMv –

2

参照変数を介してオブジェクトを使用する前にオブジェクトを作成する必要があります。そのオブジェクトがどれほど複雑であるかは関係ありません。最も一般的なケースですが、コンストラクタで初期化する必要はありません。必要に応じて、代わりに「遅延初期化」を使用することができます。

10

再帰ジェネリックデータ構造を、マップのマップのように、ではないあからさま悪い考えながら、しばしばありますあなたがリファクタリングできる何かを示す - 内側の地図は、単に地図ではなく、最初の注文オブジェクト(地図を保持している)であることがよくあります。これらの内部オブジェクトはまだ初期化する必要がありますが、多くの場合、よりクリーンで明確な開発方法です。

たとえば、Map<A,Map<B,C>>がある場合、実際にはA to Thingのマップが格納されていることがよくありますが、Thingが格納される方法は偶然にマップです。あなたは、多くの場合、クリーナーと実物がマップであるという事実を隠し、代わりのもののように定義されてMap<A,Thing>のマッピング保管しやすく、それを見つけることができます。また

public class Thing { 
    // Map is guaranteed to be initialized if a Thing exists 
    private Map<B,C> data = new Map<B,C>(); 

    // operations on data, like get and put 
    // now can have sanity checks you couldn't enforce when the map was public 
} 

を、グアバのMulitmap/Multisetユーティリティに見て、このような場合には非常に便利です。特に内部オブジェクト初期化を自動的に行います。あなたのケースでは、実際にGuava Multisetを実装したい場合はいつでも、Map<E, Integer>を実装することができます。よりきれいで明瞭。

+0

ヒントのおかげで、私はグアバのマルチセットを見ていきます。再帰的な汎用構造については、何をお勧めしますか?上記のスパム検出のコメントのように、ハッシュの2レベルのハッシュを固定したいと思っています。 featureCountクラスのようなものを作成し、それらのHashMapを作成することをお勧めしますか? –

+1

はい、それは私の答えを更新した一般的な考えです。 Guavaは一般的なJavaの問題を解決するのに役立ちます。確かにそれをチェックしてください。 – dimo414

+1

ちょっと厄介なデザインのための提案を期待して、 "HashMapのjava HashMap"をグーグルで見つけました。今、私はこれを見ています、それは一種の「奇妙な」瞬間ですが、これは完璧です。ありがとうございました! – sfarbota

2
  1. HashMapで変数を宣言しないでください。それはあまりにも限定的です。
  2. はい、class_feature_countsを初期化する必要があります。エントリを追加するので、有効なマップでなければなりません。実際には、それぞれを開始する方法が1つしかないので、コンストラクタではなく宣言時に両方を初期化します。私は今あなたがJava 7を使用していることを願っています。この方法は簡単です。

    プライベートマップ< String、Integer> classCounts = new HashMap <>();

    プライベートマップ<文字列、マップ<文字列、整数>> classFeatureCounts = new HashMap <>();

コンパイラは、タイプを<>から推測します。また、変数名を標準的なJavaのラクダのcaseスタイルに変更しました。 classCountsclassFeatureCountsは接続されていますか?

+0

ある意味では、それらは接続されており、それぞれ特定の文字列の出現回数に関する情報を保持しています。たとえば、[Programming Collective Intelligence](http://shop.oreilly.com/product/9780596529321.do)の第6章を参照してください。 )。ラクダケーシングについての頭のおかげで。 –

関連する問題