Fixed the compilation failure.

This commit is contained in:
Ali Dehghani 2019-08-04 20:39:13 +04:30
parent d72ed9ad11
commit f8e37b3162
6 changed files with 189 additions and 184 deletions

View File

@ -8,13 +8,13 @@ import java.util.Map;
*/ */
public interface Distance { public interface Distance {
/** /**
* Calculates the distance between two feature vectors. * Calculates the distance between two feature vectors.
* *
* @param f1 The first set of features. * @param f1 The first set of features.
* @param f2 The second set of features. * @param f2 The second set of features.
* @return Calculated distance. * @return Calculated distance.
* @throws IllegalArgumentException If the given feature vectors are invalid. * @throws IllegalArgumentException If the given feature vectors are invalid.
*/ */
double calculate(Map<String, Double> f1, Map<String, Double> f2); double calculate(Map<String, Double> f1, Map<String, Double> f2);
} }

View File

@ -8,16 +8,16 @@ import java.util.Map;
*/ */
public class Errors { public class Errors {
public static double sse(Map<Centroid, List<Record>> clustered, Distance distance) { public static double sse(Map<Centroid, List<Record>> clustered, Distance distance) {
double sum = 0; double sum = 0;
for (Map.Entry<Centroid, List<Record>> entry : clustered.entrySet()) { for (Map.Entry<Centroid, List<Record>> entry : clustered.entrySet()) {
Centroid centroid = entry.getKey(); Centroid centroid = entry.getKey();
for (Record record : entry.getValue()) { for (Record record : entry.getValue()) {
double d = distance.calculate(centroid.getCoordinates(), record.getFeatures()); double d = distance.calculate(centroid.getCoordinates(), record.getFeatures());
sum += Math.pow(d, 2); sum += Math.pow(d, 2);
} }
} }
return sum; return sum;
} }
} }

View File

@ -7,19 +7,19 @@ import java.util.Map;
*/ */
public class EuclideanDistance implements Distance { public class EuclideanDistance implements Distance {
@Override @Override
public double calculate(Map<String, Double> f1, Map<String, Double> f2) { public double calculate(Map<String, Double> f1, Map<String, Double> f2) {
if (f1 == null || f2 == null) if (f1 == null || f2 == null)
throw new IllegalArgumentException("Feature vectors can't be null"); throw new IllegalArgumentException("Feature vectors can't be null");
double sum = 0; double sum = 0;
for (String key : f1.keySet()) { for (String key : f1.keySet()) {
Double v1 = f1.get(key); Double v1 = f1.get(key);
Double v2 = f2.get(key); Double v2 = f2.get(key);
if (v1 != null && v2 != null) sum += Math.pow(v1 - v2, 2); if (v1 != null && v2 != null) sum += Math.pow(v1 - v2, 2);
} }
return Math.sqrt(sum); return Math.sqrt(sum);
} }
} }

View File

@ -13,40 +13,40 @@ import static java.util.stream.Collectors.toSet;
public class LastFm { public class LastFm {
private static OkHttpClient okHttp = new OkHttpClient.Builder() private static OkHttpClient okHttp = new OkHttpClient.Builder()
.addInterceptor(new LastFmService.Authenticator("put your API key here")) .addInterceptor(new LastFmService.Authenticator("put your API key here"))
.build(); .build();
private static Retrofit retrofit = new Retrofit.Builder().client(okHttp) private static Retrofit retrofit = new Retrofit.Builder().client(okHttp)
.addConverterFactory(JacksonConverterFactory.create()) .addConverterFactory(JacksonConverterFactory.create())
.baseUrl("http://ws.audioscrobbler.com/") .baseUrl("http://ws.audioscrobbler.com/")
.build(); .build();
private static LastFmService lastFm = retrofit.create(LastFmService.class); private static LastFmService lastFm = retrofit.create(LastFmService.class);
private static ObjectMapper mapper = new ObjectMapper(); private static ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
List<String> artists = getTop100Artists(); List<String> artists = getTop100Artists();
Set<String> tags = getTop100Tags(); Set<String> tags = getTop100Tags();
List<Record> records = datasetWithTaggedArtists(artists, tags); List<Record> records = datasetWithTaggedArtists(artists, tags);
Map<Centroid, List<Record>> clusters = KMeans.fit(records, 7, new EuclideanDistance(), 1000); Map<Centroid, List<Record>> clusters = KMeans.fit(records, 7, new EuclideanDistance(), 1000);
// Print the cluster configuration // Print the cluster configuration
clusters.forEach((key, value) -> { clusters.forEach((key, value) -> {
System.out.println("------------------------------ CLUSTER -----------------------------------"); System.out.println("------------------------------ CLUSTER -----------------------------------");
System.out.println(sortedCentroid(key)); System.out.println(sortedCentroid(key));
String members = String.join(", ", value.stream().map(Record::getDescription).collect(toSet())); String members = String.join(", ", value.stream().map(Record::getDescription).collect(toSet()));
System.out.print(members); System.out.print(members);
System.out.println(); System.out.println();
System.out.println(); System.out.println();
}); });
Map<String, Object> json = convertToD3CompatibleMap(clusters); Map<String, Object> json = convertToD3CompatibleMap(clusters);
System.out.println(mapper.writeValueAsString(json)); System.out.println(mapper.writeValueAsString(json));
} }
private static Map<String, Object> convertToD3CompatibleMap(Map<Centroid, List<Record>> clusters) { private static Map<String, Object> convertToD3CompatibleMap(Map<Centroid, List<Record>> clusters) {
Map<String, Object> json = new HashMap<>(); Map<String, Object> json = new HashMap<>();
@ -69,45 +69,45 @@ public class LastFm {
} }
private static String dominantGenre(Centroid centroid) { private static String dominantGenre(Centroid centroid) {
return centroid.getCoordinates().keySet().stream().limit(2).collect(Collectors.joining(", ")); return centroid.getCoordinates().keySet().stream().limit(2).collect(Collectors.joining(", "));
} }
private static Centroid sortedCentroid(Centroid key) { private static Centroid sortedCentroid(Centroid key) {
List<Map.Entry<String, Double>> entries = new ArrayList<>(key.getCoordinates().entrySet()); List<Map.Entry<String, Double>> entries = new ArrayList<>(key.getCoordinates().entrySet());
entries.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue())); entries.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue()));
Map<String, Double> sorted = new LinkedHashMap<>(); Map<String, Double> sorted = new LinkedHashMap<>();
for (Map.Entry<String, Double> entry : entries) { for (Map.Entry<String, Double> entry : entries) {
sorted.put(entry.getKey(), entry.getValue()); sorted.put(entry.getKey(), entry.getValue());
} }
return new Centroid(sorted); return new Centroid(sorted);
} }
private static List<Record> datasetWithTaggedArtists(List<String> artists, private static List<Record> datasetWithTaggedArtists(List<String> artists,
Set<String> topTags) throws IOException { Set<String> topTags) throws IOException {
List<Record> records = new ArrayList<>(); List<Record> records = new ArrayList<>();
for (String artist : artists) { for (String artist : artists) {
Map<String, Double> tags = lastFm.topTagsFor(artist).execute().body().all(); Map<String, Double> tags = lastFm.topTagsFor(artist).execute().body().all();
// Only keep popular tags. // Only keep popular tags.
tags.entrySet().removeIf(e -> !topTags.contains(e.getKey())); tags.entrySet().removeIf(e -> !topTags.contains(e.getKey()));
records.add(new Record(artist, tags)); records.add(new Record(artist, tags));
} }
return records; return records;
} }
private static Set<String> getTop100Tags() throws IOException { private static Set<String> getTop100Tags() throws IOException {
return lastFm.topTags().execute().body().all(); return lastFm.topTags().execute().body().all();
} }
private static List<String> getTop100Artists() throws IOException { private static List<String> getTop100Artists() throws IOException {
List<String> artists = new ArrayList<>(); List<String> artists = new ArrayList<>();
for (int i = 1; i <= 2; i++) { for (int i = 1; i <= 2; i++) {
artists.addAll(lastFm.topArtists(i).execute().body().all()); artists.addAll(lastFm.topArtists(i).execute().body().all());
} }
return artists; return artists;
} }
} }

View File

@ -8,6 +8,8 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonProperty;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.Interceptor; import okhttp3.Interceptor;
import okhttp3.Request; import okhttp3.Request;
@ -16,86 +18,89 @@ import retrofit2.Call;
import retrofit2.http.GET; import retrofit2.http.GET;
import retrofit2.http.Query; import retrofit2.http.Query;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
public interface LastFmService { public interface LastFmService {
@GET("/2.0/?method=chart.gettopartists&format=json&limit=50") @GET("/2.0/?method=chart.gettopartists&format=json&limit=50")
Call<Artists> topArtists(@Query("page") int page); Call<Artists> topArtists(@Query("page") int page);
@GET("/2.0/?method=artist.gettoptags&format=json&limit=20&autocorrect=1") @GET("/2.0/?method=artist.gettoptags&format=json&limit=20&autocorrect=1")
Call<Tags> topTagsFor(@Query("artist") String artist); Call<Tags> topTagsFor(@Query("artist") String artist);
@GET("/2.0/?method=chart.gettoptags&format=json&limit=100") @GET("/2.0/?method=chart.gettoptags&format=json&limit=100")
Call<TopTags> topTags(); Call<TopTags> topTags();
/** /**
* HTTP interceptor to intercept all HTTP requests and add the API key to them. * HTTP interceptor to intercept all HTTP requests and add the API key to them.
*/ */
class Authenticator implements Interceptor { class Authenticator implements Interceptor {
private final String apiKey; private final String apiKey;
Authenticator(String apiKey) { Authenticator(String apiKey) {
this.apiKey = apiKey; this.apiKey = apiKey;
} }
@Override @Override
public Response intercept(Chain chain) throws IOException { public Response intercept(Chain chain) throws IOException {
HttpUrl url = chain.request().url().newBuilder().addQueryParameter("api_key", apiKey).build(); HttpUrl url = chain.request().url().newBuilder().addQueryParameter("api_key", apiKey).build();
Request request = chain.request().newBuilder().url(url).build(); Request request = chain.request().newBuilder().url(url).build();
return chain.proceed(request); return chain.proceed(request);
} }
} }
@JsonAutoDetect(fieldVisibility = ANY) @JsonAutoDetect(fieldVisibility = ANY)
class TopTags { class TopTags {
private Map<String, Object> tags; private Map<String, Object> tags;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Set<String> all() { public Set<String> all() {
List<Map<String, Object>> topTags = (List<Map<String, Object>>) tags.get("tag"); List<Map<String, Object>> topTags = (List<Map<String, Object>>) tags.get("tag");
return topTags.stream().map(e -> ((String) e.get("name"))).collect(Collectors.toSet()); return topTags.stream().map(e -> ((String) e.get("name"))).collect(Collectors.toSet());
} }
} }
@JsonAutoDetect(fieldVisibility = ANY) @JsonAutoDetect(fieldVisibility = ANY)
class Tags { class Tags {
@JsonProperty("toptags") @JsonProperty("toptags")
private Map<String, Object> topTags; private Map<String, Object> topTags;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Map<String, Double> all() { public Map<String, Double> all() {
try { try {
Map<String, Double> all = new HashMap<>(); Map<String, Double> all = new HashMap<>();
List<Map<String, Object>> tags = (List<Map<String, Object>>) topTags.get("tag"); List<Map<String, Object>> tags = (List<Map<String, Object>>) topTags.get("tag");
for (Map<String, Object> tag : tags) { for (Map<String, Object> tag : tags) {
all.put(((String) tag.get("name")), ((Integer) tag.get("count")).doubleValue()); all.put(((String) tag.get("name")), ((Integer) tag.get("count")).doubleValue());
} }
return all; return all;
} catch (Exception e) { }
return Collections.emptyMap(); catch (Exception e) {
} return Collections.emptyMap();
} }
} }
}
@JsonAutoDetect(fieldVisibility = ANY) @JsonAutoDetect(fieldVisibility = ANY)
class Artists { class Artists {
private Map<String, Object> artists; private Map<String, Object> artists;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<String> all() { public List<String> all() {
try { try {
List<Map<String, Object>> artists = (List<Map<String, Object>>) this.artists.get("artist"); List<Map<String, Object>> artists = (List<Map<String, Object>>) this.artists.get("artist");
return artists.stream().map(e -> ((String) e.get("name"))).collect(toList()); return artists.stream().map(e -> ((String) e.get("name"))).collect(toList());
} catch (Exception e) { }
return Collections.emptyList(); catch (Exception e) {
} return Collections.emptyList();
} }
} }
}
} }

View File

@ -9,52 +9,52 @@ import java.util.Objects;
*/ */
public class Record { public class Record {
/** /**
* The record description. For example, this can be the artist name for the famous musician * The record description. For example, this can be the artist name for the famous musician
* example. * example.
*/ */
private final String description; private final String description;
/** /**
* Encapsulates all attributes and their corresponding values, i.e. features. * Encapsulates all attributes and their corresponding values, i.e. features.
*/ */
private final Map<String, Double> features; private final Map<String, Double> features;
public Record(String description, Map<String, Double> features) { public Record(String description, Map<String, Double> features) {
this.description = description; this.description = description;
this.features = features; this.features = features;
} }
public Record(Map<String, Double> features) { public Record(Map<String, Double> features) {
this("", features); this("", features);
} }
public String getDescription() { public String getDescription() {
return description; return description;
} }
public Map<String, Double> getFeatures() { public Map<String, Double> getFeatures() {
return features; return features;
} }
@Override @Override
public String toString() { public String toString() {
String prefix = description == null || description.trim().isEmpty() ? "Record" : description; String prefix = description == null || description.trim().isEmpty() ? "Record" : description;
return prefix + ": " + features; return prefix + ": " + features;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Record record = (Record) o; Record record = (Record) o;
return Objects.equals(getDescription(), record.getDescription()) && return Objects.equals(getDescription(), record.getDescription()) &&
Objects.equals(getFeatures(), record.getFeatures()); Objects.equals(getFeatures(), record.getFeatures());
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(getDescription(), getFeatures()); return Objects.hash(getDescription(), getFeatures());
} }
} }