From 5a10f94946ae4bcccfeb1b1fcbdeeb2c7433ba37 Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Wed, 7 Aug 2019 20:45:52 +0430 Subject: [PATCH] Fixed formatting issues. --- algorithms-miscellaneous-3/pom.xml | 44 +-- .../baeldung/algorithms/kmeans/Centroid.java | 50 +-- .../baeldung/algorithms/kmeans/Distance.java | 18 +- .../baeldung/algorithms/kmeans/Errors.java | 22 +- .../algorithms/kmeans/EuclideanDistance.java | 23 +- .../baeldung/algorithms/kmeans/KMeans.java | 338 +++++++++--------- .../baeldung/algorithms/kmeans/LastFm.java | 179 ++++++---- .../algorithms/kmeans/LastFmService.java | 138 +++---- .../baeldung/algorithms/kmeans/Record.java | 79 ++-- .../src/main/resources/kmeans/radial.html | 28 +- 10 files changed, 489 insertions(+), 430 deletions(-) diff --git a/algorithms-miscellaneous-3/pom.xml b/algorithms-miscellaneous-3/pom.xml index 1e5ba6650a..888f8e2e2c 100644 --- a/algorithms-miscellaneous-3/pom.xml +++ b/algorithms-miscellaneous-3/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 algorithms-miscellaneous-3 0.0.1-SNAPSHOT @@ -18,29 +18,29 @@ ${org.assertj.core.version} test - + - org.apache.commons - commons-collections4 - ${commons-collections4.version} - - - - com.google.guava - guava - ${guava.version} + org.apache.commons + commons-collections4 + ${commons-collections4.version} - - com.squareup.retrofit2 - retrofit - ${retrofit.version} - - - com.squareup.retrofit2 - converter-jackson - ${retrofit.version} - + + com.google.guava + guava + ${guava.version} + + + + com.squareup.retrofit2 + retrofit + ${retrofit.version} + + + com.squareup.retrofit2 + converter-jackson + ${retrofit.version} + @@ -59,6 +59,6 @@ 3.9.0 4.3 28.0-jre - 2.6.0 + 2.6.0 \ No newline at end of file diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Centroid.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Centroid.java index 9f3aca7916..462936541b 100644 --- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Centroid.java +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Centroid.java @@ -8,34 +8,34 @@ import java.util.Objects; */ public class Centroid { - /** - * The centroid coordinates. - */ - private final Map coordinates; + /** + * The centroid coordinates. + */ + private final Map coordinates; - public Centroid(Map coordinates) { - this.coordinates = coordinates; - } + public Centroid(Map coordinates) { + this.coordinates = coordinates; + } - public Map getCoordinates() { - return coordinates; - } + public Map getCoordinates() { + return coordinates; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Centroid centroid = (Centroid) o; - return Objects.equals(getCoordinates(), centroid.getCoordinates()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Centroid centroid = (Centroid) o; + return Objects.equals(getCoordinates(), centroid.getCoordinates()); + } - @Override - public int hashCode() { - return Objects.hash(getCoordinates()); - } + @Override + public int hashCode() { + return Objects.hash(getCoordinates()); + } - @Override - public String toString() { - return "Centroid " + coordinates; - } + @Override + public String toString() { + return "Centroid " + coordinates; + } } diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Distance.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Distance.java index 103eedb732..30723cb6b3 100644 --- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Distance.java +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Distance.java @@ -8,13 +8,13 @@ import java.util.Map; */ public interface Distance { - /** - * Calculates the distance between two feature vectors. - * - * @param f1 The first set of features. - * @param f2 The second set of features. - * @return Calculated distance. - * @throws IllegalArgumentException If the given feature vectors are invalid. - */ - double calculate(Map f1, Map f2); + /** + * Calculates the distance between two feature vectors. + * + * @param f1 The first set of features. + * @param f2 The second set of features. + * @return Calculated distance. + * @throws IllegalArgumentException If the given feature vectors are invalid. + */ + double calculate(Map f1, Map f2); } diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Errors.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Errors.java index 0fbe24c5ad..3228876051 100644 --- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Errors.java +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Errors.java @@ -8,16 +8,16 @@ import java.util.Map; */ public class Errors { - public static double sse(Map> clustered, Distance distance) { - double sum = 0; - for (Map.Entry> entry : clustered.entrySet()) { - Centroid centroid = entry.getKey(); - for (Record record : entry.getValue()) { - double d = distance.calculate(centroid.getCoordinates(), record.getFeatures()); - sum += Math.pow(d, 2); - } - } + public static double sse(Map> clustered, Distance distance) { + double sum = 0; + for (Map.Entry> entry : clustered.entrySet()) { + Centroid centroid = entry.getKey(); + for (Record record : entry.getValue()) { + double d = distance.calculate(centroid.getCoordinates(), record.getFeatures()); + sum += Math.pow(d, 2); + } + } - return sum; - } + return sum; + } } diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/EuclideanDistance.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/EuclideanDistance.java index 62d24feedf..faccd97599 100644 --- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/EuclideanDistance.java +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/EuclideanDistance.java @@ -7,19 +7,18 @@ import java.util.Map; */ public class EuclideanDistance implements Distance { - @Override - public double calculate(Map f1, Map f2) { - if (f1 == null || f2 == null) - throw new IllegalArgumentException("Feature vectors can't be null"); + @Override + public double calculate(Map f1, Map f2) { + if (f1 == null || f2 == null) throw new IllegalArgumentException("Feature vectors can't be null"); - double sum = 0; - for (String key : f1.keySet()) { - Double v1 = f1.get(key); - Double v2 = f2.get(key); + double sum = 0; + for (String key : f1.keySet()) { + Double v1 = f1.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); + } } diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/KMeans.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/KMeans.java index d8ab70b0fd..e1152a67d6 100644 --- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/KMeans.java +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/KMeans.java @@ -17,200 +17,208 @@ import static java.util.stream.Collectors.toSet; */ public class KMeans { - private KMeans() { - throw new IllegalAccessError("You shouldn't call this constructor"); - } + private KMeans() { + throw new IllegalAccessError("You shouldn't call this constructor"); + } - /** - * Will be used to generate random numbers. - */ - private static final Random random = new Random(); + /** + * Will be used to generate random numbers. + */ + private static final Random random = new Random(); - /** - * Performs the K-Means clustering algorithm on the given dataset. - * - * @param records The dataset. - * @param k Number of Clusters. - * @param distance To calculate the distance between two items. - * @param maxIterations Upper bound for the number of iterations. - * @return K clusters along with their features. - */ - public static Map> fit(List records, int k, Distance distance, int maxIterations) { - applyPreconditions(records, k, distance, maxIterations); + /** + * Performs the K-Means clustering algorithm on the given dataset. + * + * @param records The dataset. + * @param k Number of Clusters. + * @param distance To calculate the distance between two items. + * @param maxIterations Upper bound for the number of iterations. + * @return K clusters along with their features. + */ + public static Map> fit(List records, int k, Distance distance, int maxIterations) { + applyPreconditions(records, k, distance, maxIterations); - List centroids = randomCentroids(records, k); - Map> clusters = new HashMap<>(); - Map> lastState = new HashMap<>(); + List centroids = randomCentroids(records, k); + Map> clusters = new HashMap<>(); + Map> lastState = new HashMap<>(); - // iterate for a pre-defined number of times - for (int i = 0; i < maxIterations; i++) { - boolean isLastIteration = i == maxIterations - 1; + // iterate for a pre-defined number of times + for (int i = 0; i < maxIterations; i++) { + boolean isLastIteration = i == maxIterations - 1; - // in each iteration we should find the nearest centroid for each record - for (Record record : records) { - Centroid centroid = nearestCentroid(record, centroids, distance); - assignToCluster(clusters, record, centroid); - } + // in each iteration we should find the nearest centroid for each record + for (Record record : records) { + Centroid centroid = nearestCentroid(record, centroids, distance); + assignToCluster(clusters, record, centroid); + } - // if the assignment does not change, then the algorithm terminates - boolean shouldTerminate = isLastIteration || clusters.equals(lastState); - lastState = clusters; - if (shouldTerminate) break; + // if the assignment does not change, then the algorithm terminates + boolean shouldTerminate = isLastIteration || clusters.equals(lastState); + lastState = clusters; + if (shouldTerminate) break; - // at the end of each iteration we should relocate the centroids - centroids = relocateCentroids(clusters); - clusters = new HashMap<>(); - } + // at the end of each iteration we should relocate the centroids + centroids = relocateCentroids(clusters); + clusters = new HashMap<>(); + } - return lastState; - } + return lastState; + } - /** - * Move all cluster centroids to the average of all assigned features. - * - * @param clusters The current cluster configuration. - * @return Collection of new and relocated centroids. - */ - private static List relocateCentroids(Map> clusters) { - return clusters.entrySet().stream() - .map(e -> average(e.getKey(), e.getValue())).collect(toList()); - } + /** + * Move all cluster centroids to the average of all assigned features. + * + * @param clusters The current cluster configuration. + * @return Collection of new and relocated centroids. + */ + private static List relocateCentroids(Map> clusters) { + return clusters + .entrySet() + .stream() + .map(e -> average(e.getKey(), e.getValue())) + .collect(toList()); + } - /** - * Moves the given centroid to the average position of all assigned features. If - * the centroid has no feature in its cluster, then there would be no need for a - * relocation. Otherwise, for each entry we calculate the average of all records - * first by summing all the entries and then dividing the final summation value by - * the number of records. - * - * @param centroid The centroid to move. - * @param records The assigned features. - * @return The moved centroid. - */ - private static Centroid average(Centroid centroid, List records) { - // if this cluster is empty, then we shouldn't move the centroid - if (records == null || records.isEmpty()) return centroid; + /** + * Moves the given centroid to the average position of all assigned features. If + * the centroid has no feature in its cluster, then there would be no need for a + * relocation. Otherwise, for each entry we calculate the average of all records + * first by summing all the entries and then dividing the final summation value by + * the number of records. + * + * @param centroid The centroid to move. + * @param records The assigned features. + * @return The moved centroid. + */ + private static Centroid average(Centroid centroid, List records) { + // if this cluster is empty, then we shouldn't move the centroid + if (records == null || records.isEmpty()) return centroid; - // Since some records don't have all possible attributes, we initialize - // average coordinates equal to current centroid coordinates - Map average = centroid.getCoordinates(); + // Since some records don't have all possible attributes, we initialize + // average coordinates equal to current centroid coordinates + Map average = centroid.getCoordinates(); - // The average function works correctly if we clear all coordinates corresponding - // to present record attributes - records.stream().flatMap(e -> e.getFeatures().keySet().stream()) - .forEach(k -> average.put(k, 0.0)); + // The average function works correctly if we clear all coordinates corresponding + // to present record attributes + records + .stream() + .flatMap(e -> e + .getFeatures() + .keySet() + .stream()) + .forEach(k -> average.put(k, 0.0)); - for (Record record : records) { - record.getFeatures().forEach( - (k, v) -> average.compute(k, (k1, currentValue) -> v + currentValue) - ); - } + for (Record record : records) { + record + .getFeatures() + .forEach((k, v) -> average.compute(k, (k1, currentValue) -> v + currentValue)); + } - average.forEach((k, v) -> average.put(k, v / records.size())); + average.forEach((k, v) -> average.put(k, v / records.size())); - return new Centroid(average); - } + return new Centroid(average); + } - /** - * Assigns a feature vector to the given centroid. If this is the first assignment for this centroid, - * first we should create the list. - * - * @param clusters The current cluster configuration. - * @param record The feature vector. - * @param centroid The centroid. - */ - private static void assignToCluster(Map> clusters, - Record record, Centroid centroid) { - clusters.compute(centroid, (key, list) -> { - if (list == null) { - list = new ArrayList<>(); - } + /** + * Assigns a feature vector to the given centroid. If this is the first assignment for this centroid, + * first we should create the list. + * + * @param clusters The current cluster configuration. + * @param record The feature vector. + * @param centroid The centroid. + */ + private static void assignToCluster(Map> clusters, Record record, Centroid centroid) { + clusters.compute(centroid, (key, list) -> { + if (list == null) { + list = new ArrayList<>(); + } - list.add(record); - return list; - }); - } + list.add(record); + return list; + }); + } - /** - * With the help of the given distance calculator, iterates through centroids and finds the - * nearest one to the given record. - * - * @param record The feature vector to find a centroid for. - * @param centroids Collection of all centroids. - * @param distance To calculate the distance between two items. - * @return The nearest centroid to the given feature vector. - */ - private static Centroid nearestCentroid(Record record, List centroids, - Distance distance) { - double minimumDistance = Double.MAX_VALUE; - Centroid nearest = null; + /** + * With the help of the given distance calculator, iterates through centroids and finds the + * nearest one to the given record. + * + * @param record The feature vector to find a centroid for. + * @param centroids Collection of all centroids. + * @param distance To calculate the distance between two items. + * @return The nearest centroid to the given feature vector. + */ + private static Centroid nearestCentroid(Record record, List centroids, Distance distance) { + double minimumDistance = Double.MAX_VALUE; + Centroid nearest = null; - for (Centroid centroid : centroids) { - double currentDistance = distance.calculate(record.getFeatures(), centroid.getCoordinates()); + for (Centroid centroid : centroids) { + double currentDistance = distance.calculate(record.getFeatures(), centroid.getCoordinates()); - if (currentDistance < minimumDistance) { - minimumDistance = currentDistance; - nearest = centroid; - } - } + if (currentDistance < minimumDistance) { + minimumDistance = currentDistance; + nearest = centroid; + } + } - return nearest; - } + return nearest; + } - /** - * Generates k random centroids. Before kicking-off the centroid generation process, - * first we calculate the possible value range for each attribute. Then when - * we're going to generate the centroids, we generate random coordinates in - * the [min, max] range for each attribute. - * - * @param records The dataset which helps to calculate the [min, max] range for - * each attribute. - * @param k Number of clusters. - * @return Collections of randomly generated centroids. - */ - private static List randomCentroids(List records, int k) { - List centroids = new ArrayList<>(); - Map maxs = new HashMap<>(); - Map mins = new HashMap<>(); + /** + * Generates k random centroids. Before kicking-off the centroid generation process, + * first we calculate the possible value range for each attribute. Then when + * we're going to generate the centroids, we generate random coordinates in + * the [min, max] range for each attribute. + * + * @param records The dataset which helps to calculate the [min, max] range for + * each attribute. + * @param k Number of clusters. + * @return Collections of randomly generated centroids. + */ + private static List randomCentroids(List records, int k) { + List centroids = new ArrayList<>(); + Map maxs = new HashMap<>(); + Map mins = new HashMap<>(); - for (Record record : records) { - record.getFeatures().forEach((key, value) -> { - // compares the value with the current max and choose the bigger value between them - maxs.compute(key, (k1, max) -> max == null || value > max ? value : max); + for (Record record : records) { + record + .getFeatures() + .forEach((key, value) -> { + // compares the value with the current max and choose the bigger value between them + maxs.compute(key, (k1, max) -> max == null || value > max ? value : max); - // compare the value with the current min and choose the smaller value between them - mins.compute(key, (k1, min) -> min == null || value < min ? value : min); - }); - } + // compare the value with the current min and choose the smaller value between them + mins.compute(key, (k1, min) -> min == null || value < min ? value : min); + }); + } - Set attributes = records.stream() - .flatMap(e -> e.getFeatures().keySet().stream()).collect(toSet()); - for (int i = 0; i < k; i++) { - Map coordinates = new HashMap<>(); - for (String attribute : attributes) { - double max = maxs.get(attribute); - double min = mins.get(attribute); - coordinates.put(attribute, random.nextDouble() * (max - min) + min); - } + Set attributes = records + .stream() + .flatMap(e -> e + .getFeatures() + .keySet() + .stream()) + .collect(toSet()); + for (int i = 0; i < k; i++) { + Map coordinates = new HashMap<>(); + for (String attribute : attributes) { + double max = maxs.get(attribute); + double min = mins.get(attribute); + coordinates.put(attribute, random.nextDouble() * (max - min) + min); + } - centroids.add(new Centroid(coordinates)); - } + centroids.add(new Centroid(coordinates)); + } - return centroids; - } + return centroids; + } - private static void applyPreconditions(List records, int k, - Distance distance, int maxIterations) { - if (records == null || records.isEmpty()) - throw new IllegalArgumentException("The dataset can't be empty"); + private static void applyPreconditions(List records, int k, Distance distance, int maxIterations) { + if (records == null || records.isEmpty()) throw new IllegalArgumentException("The dataset can't be empty"); - if (k <= 1) - throw new IllegalArgumentException("It doesn't make sense to have less than or equal to 1 cluster"); + if (k <= 1) throw new IllegalArgumentException("It doesn't make sense to have less than or equal to 1 cluster"); - if (distance == null) - throw new IllegalArgumentException("The distance calculator is required"); + if (distance == null) throw new IllegalArgumentException("The distance calculator is required"); - if (maxIterations <= 0) - throw new IllegalArgumentException("Max iterations should be a positive number"); - } + if (maxIterations <= 0) throw new IllegalArgumentException("Max iterations should be a positive number"); + } } diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFm.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFm.java index 7d241d3a79..4694a845af 100644 --- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFm.java +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFm.java @@ -19,101 +19,126 @@ import static java.util.stream.Collectors.toSet; public class LastFm { - private static OkHttpClient okHttp = new OkHttpClient.Builder() - .addInterceptor(new LastFmService.Authenticator("put your API key here")) - .build(); + private static OkHttpClient okHttp = new OkHttpClient.Builder() + .addInterceptor(new LastFmService.Authenticator("put your API key here")) + .build(); - private static Retrofit retrofit = new Retrofit.Builder().client(okHttp) - .addConverterFactory(JacksonConverterFactory.create()) - .baseUrl("http://ws.audioscrobbler.com/") - .build(); + private static Retrofit retrofit = new Retrofit.Builder() + .client(okHttp) + .addConverterFactory(JacksonConverterFactory.create()) + .baseUrl("http://ws.audioscrobbler.com/") + .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 { - List artists = getTop100Artists(); - Set tags = getTop100Tags(); - List records = datasetWithTaggedArtists(artists, tags); + public static void main(String[] args) throws IOException { + List artists = getTop100Artists(); + Set tags = getTop100Tags(); + List records = datasetWithTaggedArtists(artists, tags); - Map> clusters = KMeans.fit(records, 7, new EuclideanDistance(), 1000); - // Print the cluster configuration - clusters.forEach((key, value) -> { - System.out.println("------------------------------ CLUSTER -----------------------------------"); + Map> clusters = KMeans.fit(records, 7, new EuclideanDistance(), 1000); + // Print the cluster configuration + clusters.forEach((key, value) -> { + System.out.println("------------------------------ CLUSTER -----------------------------------"); - System.out.println(sortedCentroid(key)); - String members = String.join(", ", value.stream().map(Record::getDescription).collect(toSet())); - System.out.print(members); + System.out.println(sortedCentroid(key)); + String members = String.join(", ", value + .stream() + .map(Record::getDescription) + .collect(toSet())); + System.out.print(members); - System.out.println(); - System.out.println(); - }); + System.out.println(); + System.out.println(); + }); - Map json = convertToD3CompatibleMap(clusters); - System.out.println(mapper.writeValueAsString(json)); - } + Map json = convertToD3CompatibleMap(clusters); + System.out.println(mapper.writeValueAsString(json)); + } - private static Map convertToD3CompatibleMap(Map> clusters) { - Map json = new HashMap<>(); - json.put("name", "Musicians"); - List> children = new ArrayList<>(); - clusters.forEach((key, value) -> { - Map child = new HashMap<>(); - child.put("name", dominantGenre(sortedCentroid(key))); - List> nested = new ArrayList<>(); - for (Record record : value) { - nested.add(Collections.singletonMap("name", record.getDescription())); - } - child.put("children", nested); + private static Map convertToD3CompatibleMap(Map> clusters) { + Map json = new HashMap<>(); + json.put("name", "Musicians"); + List> children = new ArrayList<>(); + clusters.forEach((key, value) -> { + Map child = new HashMap<>(); + child.put("name", dominantGenre(sortedCentroid(key))); + List> nested = new ArrayList<>(); + for (Record record : value) { + nested.add(Collections.singletonMap("name", record.getDescription())); + } + child.put("children", nested); + children.add(child); + }); + json.put("children", children); + return json; + } - children.add(child); - }); - json.put("children", children); - return json; - } + private static String dominantGenre(Centroid centroid) { + return centroid + .getCoordinates() + .keySet() + .stream() + .limit(2) + .collect(Collectors.joining(", ")); + } - private static String dominantGenre(Centroid centroid) { - return centroid.getCoordinates().keySet().stream().limit(2).collect(Collectors.joining(", ")); - } + private static Centroid sortedCentroid(Centroid key) { + List> entries = new ArrayList<>(key + .getCoordinates() + .entrySet()); + entries.sort((e1, e2) -> e2 + .getValue() + .compareTo(e1.getValue())); - private static Centroid sortedCentroid(Centroid key) { - List> entries = new ArrayList<>(key.getCoordinates().entrySet()); - entries.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue())); + Map sorted = new LinkedHashMap<>(); + for (Map.Entry entry : entries) { + sorted.put(entry.getKey(), entry.getValue()); + } - Map sorted = new LinkedHashMap<>(); - for (Map.Entry entry : entries) { - sorted.put(entry.getKey(), entry.getValue()); - } + return new Centroid(sorted); + } - return new Centroid(sorted); - } + private static List datasetWithTaggedArtists(List artists, Set topTags) throws IOException { + List records = new ArrayList<>(); + for (String artist : artists) { + Map tags = lastFm + .topTagsFor(artist) + .execute() + .body() + .all(); - private static List datasetWithTaggedArtists(List artists, - Set topTags) throws IOException { - List records = new ArrayList<>(); - for (String artist : artists) { - Map tags = lastFm.topTagsFor(artist).execute().body().all(); + // Only keep popular tags. + tags + .entrySet() + .removeIf(e -> !topTags.contains(e.getKey())); - // Only keep popular tags. - tags.entrySet().removeIf(e -> !topTags.contains(e.getKey())); + records.add(new Record(artist, tags)); + } + return records; + } - records.add(new Record(artist, tags)); - } - return records; - } + private static Set getTop100Tags() throws IOException { + return lastFm + .topTags() + .execute() + .body() + .all(); + } - private static Set getTop100Tags() throws IOException { - return lastFm.topTags().execute().body().all(); - } + private static List getTop100Artists() throws IOException { + List artists = new ArrayList<>(); + for (int i = 1; i <= 2; i++) { + artists.addAll(lastFm + .topArtists(i) + .execute() + .body() + .all()); + } - private static List getTop100Artists() throws IOException { - List artists = new ArrayList<>(); - for (int i = 1; i <= 2; i++) { - artists.addAll(lastFm.topArtists(i).execute().body().all()); - } - - return artists; - } + return artists; + } } diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFmService.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFmService.java index cfc8e8d478..db57deb888 100644 --- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFmService.java +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFmService.java @@ -23,84 +23,96 @@ import static java.util.stream.Collectors.toList; public interface LastFmService { - @GET("/2.0/?method=chart.gettopartists&format=json&limit=50") - Call topArtists(@Query("page") int page); + @GET("/2.0/?method=chart.gettopartists&format=json&limit=50") + Call topArtists(@Query("page") int page); - @GET("/2.0/?method=artist.gettoptags&format=json&limit=20&autocorrect=1") - Call topTagsFor(@Query("artist") String artist); + @GET("/2.0/?method=artist.gettoptags&format=json&limit=20&autocorrect=1") + Call topTagsFor(@Query("artist") String artist); - @GET("/2.0/?method=chart.gettoptags&format=json&limit=100") - Call topTags(); + @GET("/2.0/?method=chart.gettoptags&format=json&limit=100") + Call topTags(); - /** - * HTTP interceptor to intercept all HTTP requests and add the API key to them. - */ - class Authenticator implements Interceptor { + /** + * HTTP interceptor to intercept all HTTP requests and add the API key to them. + */ + class Authenticator implements Interceptor { - private final String apiKey; + private final String apiKey; - Authenticator(String apiKey) { - this.apiKey = apiKey; - } + Authenticator(String apiKey) { + this.apiKey = apiKey; + } - @Override - public Response intercept(Chain chain) throws IOException { - HttpUrl url = chain.request().url().newBuilder().addQueryParameter("api_key", apiKey).build(); - Request request = chain.request().newBuilder().url(url).build(); + @Override + public Response intercept(Chain chain) throws IOException { + HttpUrl url = chain + .request() + .url() + .newBuilder() + .addQueryParameter("api_key", apiKey) + .build(); + Request request = chain + .request() + .newBuilder() + .url(url) + .build(); - return chain.proceed(request); - } - } + return chain.proceed(request); + } + } - @JsonAutoDetect(fieldVisibility = ANY) - class TopTags { + @JsonAutoDetect(fieldVisibility = ANY) + class TopTags { - private Map tags; + private Map tags; - @SuppressWarnings("unchecked") - public Set all() { - List> topTags = (List>) tags.get("tag"); - return topTags.stream().map(e -> ((String) e.get("name"))).collect(Collectors.toSet()); - } - } + @SuppressWarnings("unchecked") + public Set all() { + List> topTags = (List>) tags.get("tag"); + return topTags + .stream() + .map(e -> ((String) e.get("name"))) + .collect(Collectors.toSet()); + } + } - @JsonAutoDetect(fieldVisibility = ANY) - class Tags { + @JsonAutoDetect(fieldVisibility = ANY) + class Tags { - @JsonProperty("toptags") - private Map topTags; + @JsonProperty("toptags") private Map topTags; - @SuppressWarnings("unchecked") - public Map all() { - try { - Map all = new HashMap<>(); - List> tags = (List>) topTags.get("tag"); - for (Map tag : tags) { - all.put(((String) tag.get("name")), ((Integer) tag.get("count")).doubleValue()); - } + @SuppressWarnings("unchecked") + public Map all() { + try { + Map all = new HashMap<>(); + List> tags = (List>) topTags.get("tag"); + for (Map tag : tags) { + all.put(((String) tag.get("name")), ((Integer) tag.get("count")).doubleValue()); + } - return all; - } - catch (Exception e) { - return Collections.emptyMap(); - } - } - } + return all; + } catch (Exception e) { + return Collections.emptyMap(); + } + } + } - @JsonAutoDetect(fieldVisibility = ANY) - class Artists { + @JsonAutoDetect(fieldVisibility = ANY) + class Artists { - private Map artists; + private Map artists; - @SuppressWarnings("unchecked") - public List all() { - try { - List> artists = (List>) this.artists.get("artist"); - return artists.stream().map(e -> ((String) e.get("name"))).collect(toList()); - } - catch (Exception e) { - return Collections.emptyList(); - } - } - } + @SuppressWarnings("unchecked") + public List all() { + try { + List> artists = (List>) this.artists.get("artist"); + return artists + .stream() + .map(e -> ((String) e.get("name"))) + .collect(toList()); + } catch (Exception e) { + return Collections.emptyList(); + } + } + } } diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Record.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Record.java index 6aa2c3ba90..a29e3e054b 100644 --- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Record.java +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Record.java @@ -9,52 +9,53 @@ import java.util.Objects; */ public class Record { - /** - * The record description. For example, this can be the artist name for the famous musician - * example. - */ - private final String description; + /** + * The record description. For example, this can be the artist name for the famous musician + * example. + */ + private final String description; - /** - * Encapsulates all attributes and their corresponding values, i.e. features. - */ - private final Map features; + /** + * Encapsulates all attributes and their corresponding values, i.e. features. + */ + private final Map features; - public Record(String description, Map features) { - this.description = description; - this.features = features; - } + public Record(String description, Map features) { + this.description = description; + this.features = features; + } - public Record(Map features) { - this("", features); - } + public Record(Map features) { + this("", features); + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public Map getFeatures() { - return features; - } + public Map getFeatures() { + return features; + } - @Override - public String toString() { - String prefix = description == null || description.trim().isEmpty() ? "Record" : description; + @Override + public String toString() { + String prefix = description == null || description + .trim() + .isEmpty() ? "Record" : description; - return prefix + ": " + features; - } + return prefix + ": " + features; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Record record = (Record) o; - return Objects.equals(getDescription(), record.getDescription()) && - Objects.equals(getFeatures(), record.getFeatures()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Record record = (Record) o; + return Objects.equals(getDescription(), record.getDescription()) && Objects.equals(getFeatures(), record.getFeatures()); + } - @Override - public int hashCode() { - return Objects.hash(getDescription(), getFeatures()); - } + @Override + public int hashCode() { + return Objects.hash(getDescription(), getFeatures()); + } } diff --git a/algorithms-miscellaneous-3/src/main/resources/kmeans/radial.html b/algorithms-miscellaneous-3/src/main/resources/kmeans/radial.html index d7f9b74cbc..e7e7403871 100644 --- a/algorithms-miscellaneous-3/src/main/resources/kmeans/radial.html +++ b/algorithms-miscellaneous-3/src/main/resources/kmeans/radial.html @@ -6,9 +6,11 @@ stroke: steelblue; stroke-width: 1.5px; } + .node { font: 10px sans-serif; } + .link { fill: none; stroke: #ccc; @@ -21,15 +23,19 @@ var diameter = 1100; var tree = d3.layout.tree() .size([360, diameter / 2 - 300]) - .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; }); + .separation(function (a, b) { + return (a.parent == b.parent ? 1 : 2) / a.depth; + }); var diagonal = d3.svg.diagonal.radial() - .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; }); + .projection(function (d) { + return [d.y, d.x / 180 * Math.PI]; + }); var svg = d3.select("body").append("svg") .attr("width", diameter) .attr("height", diameter - 150) .append("g") .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")"); - d3.json("lastfm.json", function(error, root) { + d3.json("lastfm.json", function (error, root) { var nodes = tree.nodes(root), links = tree.links(nodes); var link = svg.selectAll(".link") @@ -41,14 +47,22 @@ .data(nodes) .enter().append("g") .attr("class", "node") - .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; }) + .attr("transform", function (d) { + return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; + }) node.append("circle") .attr("r", 4.5); node.append("text") .attr("dy", ".31em") - .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; }) - .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; }) - .text(function(d) { return d.name; }); + .attr("text-anchor", function (d) { + return d.x < 180 ? "start" : "end"; + }) + .attr("transform", function (d) { + return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; + }) + .text(function (d) { + return d.name; + }); }); d3.select(self.frameElement).style("height", diameter - 150 + "px"); \ No newline at end of file