5

私はScalaでWekaを使用しています(構文は実質的にJavaと同じですが)。SimpleKMeans Clustererを使用してデータを評価しようとしていますが、Clustererは文字列データを受け入れません。文字列データでクラスター化したくありません。ポイントにラベルを付けるために使用したいだけです。

これが私が使用しているデータです:

@relation Locations
@attribute ID string
@attribute Latitude numeric
@attribute Longitude numeric
@data
'Carnegie Mellon University', 40.443064, -79.944163
'Stanford University', 37.427539, -122.170169
'Massachusetts Institute of Technology', 42.358866, -71.093823
'University of California Berkeley', 37.872166, -122.259444
'University of Washington', 47.65601, -122.30934
'University of Illinois Urbana Champaign', 40.091022, -88.229992
'University of Southern California', 34.019372, -118.28611
'University of California San Diego', 32.881494, -117.243079

ご覧のとおり、これは基本的にx座標平面とy座標平面上の点の集まりです。パターンの値はごくわずかです。これは、Wekaを使用する際の演習にすぎません。

これが私に問題を引き起こしているコードです:

val instance = new Instances(new StringReader(wekaHeader + wekaData))

val simpleKMeans = new SimpleKMeans()
simpleKMeans.buildClusterer(instance)

val eval = new ClusterEvaluation()
eval.setClusterer(simpleKMeans)
eval.evaluateClusterer(new Instances(instance))

Logger.info(eval.clusterResultsToString)

次のエラーが発生しますsimpleKMeans.buildClusterer(instance)

[UnsupportedAttributeTypeException:weka.clusterers.SimpleKMeans:文字列属性を処理できません!]

クラスタリングの実行中にWekaにIDを保持させるにはどうすればよいですか?


これをトラブルシューティングするために私が取った他のいくつかのステップは次のとおりです。

Weka Explorerを使用して、このデータをCSVとしてロードしました。

ID, Latitude, Longitude
'Carnegie Mellon University', 40.443064, -79.944163
'Stanford University', 37.427539, -122.170169
'Massachusetts Institute of Technology', 42.358866, -71.093823
'University of California Berkeley', 37.872166, -122.259444
'University of Washington', 47.65601, -122.30934
'University of Illinois Urbana Champaign', 40.091022, -88.229992
'University of Southern California', 34.019372, -118.28611
'University of California San Diego', 32.881494, -117.243079

これは、WekaExplorerで実行したいことを実行します。Wekaはポイントをクラスター化し、各ポイントを識別するためにID列を保持します。私は自分のコードでこれを行いますが、追加のファイルを生成せずにこれを実行しようとしています。Weka Java APIからわかるように、はARFFとしてのみInstances解釈されます。java.io.Reader

次のコードも試しました。

val instance = new Instances(new StringReader(wekaHeader + wekaData))
instance.deleteAttributeAt(0)

val simpleKMeans = new SimpleKMeans()
simpleKMeans.buildClusterer(instance)

val eval = new ClusterEvaluation()
eval.setClusterer(simpleKMeans)
eval.evaluateClusterer(new Instances(instance))

Logger.info(eval.clusterResultsToString)

これは私のコードで機能し、結果を表示します。これは、Wekaが一般的に機能していることを証明していますが、ID属性を削除しているため、クラスター化されたポイントを元の値に実際にマップすることはできません。

4

2 に答える 2

5

私は自分の質問に答えています。そうすることで、私が対処したい2つの問題があります。

  • CSVが文字列値で機能する理由
  • クラスター評価からクラスター情報を取得する方法

セントリーがコメントで指摘しているように、CSVから読み込まれると、IDは実際には名目上の属性に変換されます

ARFFデータが次の形式である必要がある場合(Instancesオブジェクトがから作成される私の例のようにStringReader)、StringToNominalフィルターを適用できます。

  val instances = new Instances(new StringReader(wekaHeader + wekaData))

  val filter = new StringToNominal()
  filter.setAttributeRange("first")
  filter.setInputFormat(instances)

  val filteredInstance = Filter.useFilter(instances, filter)

  val simpleKMeans = new SimpleKMeans()
  simpleKMeans.buildClusterer(instance)
  ...

これにより、「文字列」値をクラスタリングで使用できますが、実際には公称値として扱われます。クラスタリングには影響しませんが(IDが一意の場合)、期待どおりの評価にはなりません。次の問題に進みます。


cluster: Int -> Array[(ID, latitude, longitude)]またはのようなクラスターとデータの素敵なマップを取得できることを望んでいましたID -> cluster: Int。ただし、クラスターの結果はそれほど便利ではありません。ここ数日の私の経験では、データの各ポイントのクラスターを見つけるために使用できる2つのアプローチがあります。

クラスター割り当てを取得するにsimpleKMeans.getAssignmentsは、各データ要素のクラスター割り当てである整数の配列を返します。整数の配列は元のデータ項目と同じ順序であり、元のデータ項目に手動で関連付ける必要があります。これは、Scalazipでデータ項目の元のリストのメソッドを使用してから、groupByまたはなどの他のメソッドを使用mapして、お気に入りの形式でコレクションを取得することで簡単に実行できます。この方法だけではID属性をまったく使用せず、ID属性をデータポイントから完全に省略できることに注意してください。

simpleKMeans.getClusterCentroidsただし、またはを使用してクラスターセンターを取得することもできますeval.clusterResultsToString()。私はこれをあまり使用していませんが、ID属性はここのクラスターセンターから回復できるようです。私の知る限り、これはIDデータをクラスター評価から利用または回復できる唯一の状況です。

于 2013-03-28T01:03:10.270 に答える
0

数百万行のCSVファイルの1行に文字列値があるときに同じエラーが発生しました。これが私がどの行が文字列値を持っているかを理解する方法です。

例外「文字列属性を処理できません!」行番号についての手がかりはありません。したがって:

  • CSVファイルをWekaExplorerGUIにインポートし、*。arffファイルを作成しました。
  • 次に、以下に示すように、最初に*.arrfファイルでタイプを文字列から数値に手動で変更しました。
  • その後、*。arffファイルを使用してクラスターを構築しようとしました。
  • 例外の一部として正確な行番号を取得しました
  • * .arffファイルからその行を削除して、再度ロードしました。問題なく動作しました。

変換された文字列->*.arffファイルの数値

@attribute total numeric
@attribute avgDailyMB numeric
@attribute mccMncCount numeric
@attribute operatorCount numeric
@attribute authSuccessRate numeric
@attribute totalMonthlyRequets numeric
@attribute tokenCount numeric
@attribute osVersionCount numeric
@attribute totalAuthUserIds numeric
@attribute makeCount numeric
@attribute modelCount numeric
@attribute maxDailyRequests numeric
@attribute avgDailyRequests numeric

エラーにより正確な行番号が報告されました

java.io.IOException: number expected, read Token[value.total], line 1750464
    at weka.core.converters.ArffLoader$ArffReader.errorMessage(ArffLoader.java:354)
    at weka.core.converters.ArffLoader$ArffReader.getInstanceFull(ArffLoader.java:728)
    at weka.core.converters.ArffLoader$ArffReader.getInstance(ArffLoader.java:545)
    at weka.core.converters.ArffLoader$ArffReader.readInstance(ArffLoader.java:514)
    at weka.core.converters.ArffLoader$ArffReader.readInstance(ArffLoader.java:500)
    at weka.core.Instances.<init>(Instances.java:138)
    at com.lokendra.dissertation.ModelingUtils.kMeans(ModelingUtils.java:50)
    at com.lokendra.dissertation.ModelingUtils.main(ModelingUtils.java:28)
于 2017-09-18T17:28:18.150 に答える