Java의 컬렉션에서 분포 계산

소스 노드 : 1734738

숫자 모음(또는 검사하려는 필드가 있는 개체)을 해당 숫자의 분포로 바꾸는 것은 일반적인 통계 기술이며 보고 및 데이터 기반 응용 프로그램의 다양한 컨텍스트에서 사용됩니다.

주어진 컬렉션:

1, 1, 2, 1, 2, 3, 1, 4, 5, 1, 3

분포를 개수(각 요소의 빈도)로 검사하고 결과를 맵에 저장할 수 있습니다.

{
"1": 5,
"2": 2,
"3": 2,
"4": 1,
"5": 1
}

또는 정상화 값의 총 수를 기반으로 하는 값 – 따라서 백분율로 표현:

{
"1": 0.45,
"2": 0.18,
"3": 0.18,
"4": 0.09,
"5": 0.09
}

또는 이러한 백분율을 0..100 대신 형식 0..1 형식입니다.

이 가이드에서는 기본 유형과 애플리케이션에서 보고할 필드가 있는 개체를 모두 사용하여 컬렉션에서 분포를 계산하는 방법을 살펴보겠습니다.

Java에 기능적 프로그래밍 지원이 추가되어 분포 계산이 그 어느 때보다 쉬워졌습니다. 우리는 숫자 모음과 Books:

public class Book {

    private String id;
    private String name;
    private String author;
    private long pageNumber;
    private long publishedYear;

   
}

Java에서 컬렉션 분포 계산

먼저 기본 유형에 대한 분포를 계산하는 방법을 살펴보겠습니다. 개체로 작업하면 도메인 클래스에서 사용자 정의 메서드를 호출하여 계산에 더 많은 유연성을 제공할 수 있습니다.

기본적으로 백분율을 다음의 두 배로 표시합니다. 0.00100.00.

기본 유형

정수 목록을 만들고 분포를 인쇄해 보겠습니다.

List integerList = List.of(1, 1, 2, 1, 2, 3, 1, 4, 5, 1, 3);
System.out.println(calculateIntegerDistribution(integerList));

분포는 다음과 같이 계산됩니다.

public static Map calculateIntegerDistribution(List list) {
    return list.stream()
            .collect(Collectors.groupingBy(Integer::intValue,
                    Collectors.collectingAndThen(Collectors.counting(),
                            count -> (Double.parseDouble(String.format("%.2f", count * 100.00 / list.size()))))));
}

이 메서드는 목록을 수락하고 스트리밍합니다. 스트리밍되는 동안 값은 그룹화 그들의 정수 값 – 그리고 그들의 값은 계산 된 사용 Collectors.counting(), 수집되기 전에 Map 여기서 키는 입력 값을 나타내고 double은 분포에서 백분율을 나타냅니다.

여기서 핵심적인 방법은 collect() 받아들이는 두 명의 수집가. 키 수집기는 단순히 키 값(입력 요소)별로 그룹화하여 수집합니다. 가치 수집가는 다음을 통해 수집합니다. collectingAndThen() 방법을 통해 값을 세다 다음과 같은 다른 형식으로 형식을 지정합니다. count * 100.00 / list.size() 이렇게 하면 계산된 요소를 백분율로 표현할 수 있습니다.

{1=45.45, 2=18.18, 3=18.18, 4=9.09, 5=9.09}

값 또는 키로 분포 정렬

분포를 만들 때 일반적으로 값을 정렬하려고 합니다. 대부분의 경우 이것은 다음과 같습니다. . 자바 HashMaps 삽입 순서 유지를 보장하지 않음, 그래서 우리는 LinkedHashMap 하는 것입니다. 또한 크기가 훨씬 작고 관리하기가 훨씬 쉬워졌기 때문에 지도를 다시 스트리밍하고 다시 수집하는 것이 가장 쉽습니다.

이전 작업은 처리하는 키의 수에 따라 수천 개의 레코드를 작은 맵으로 빠르게 축소할 수 있으므로 다시 스트리밍하는 데 비용이 많이 들지 않습니다.

public static Map calculateIntegerDistribution(List list) {
    return list.stream()
            .collect(Collectors.groupingBy(Integer::intValue,
                    Collectors.collectingAndThen(Collectors.counting(),
                            count -> (Double.parseDouble(String.format("%.2f", count.doubleValue() / list.size()))))))
            
            
            .entrySet()
            .stream()
            .sorted(Map.Entry.comparingByKey())
            .collect(Collectors.toMap(e -> Integer.parseInt(e.getKey().toString()),
                    Map.Entry::getValue,
                    (a, b) -> {
                        throw new AssertionError();
                    },
                    LinkedHashMap::new));
}

사물

객체에 대해 어떻게 할 수 있습니까? 같은 논리가 적용됩니다! 식별 기능 대신(Integer::intValue), 대신 원하는 필드(예: 책의 출판 연도)를 사용합니다. 몇 권의 책을 만들어 목록에 저장한 다음 출판 연도의 분포를 계산해 보겠습니다.

모범 사례, 업계에서 인정하는 표준 및 포함된 치트 시트가 포함된 Git 학습에 대한 실습 가이드를 확인하십시오. 인터넷 검색 Git 명령을 중지하고 실제로 배움 이것!

Book book1 = new Book("001", "Our Mathematical Universe", "Max Tegmark", 432, 2014);
Book book2 = new Book("002", "Life 3.0", "Max Tegmark", 280, 2017);
Book book3 = new Book("003", "Sapiens", "Yuval Noah Harari", 443, 2011);
Book book4 = new Book("004", "Steve Jobs", "Water Isaacson", 656, 2011);

List books = Arrays.asList(book1, book2, book3, book4);

분포를 계산해 보자. publishedYear 들:

public static Map calculateDistribution(List books) {
    return books.stream()
            .collect(Collectors.groupingBy(Book::getPublishedYear,
                    Collectors.collectingAndThen(Collectors.counting(),
                            count -> (Double.parseDouble(String.format("%.2f", count * 100.00 / books.size()))))))
            
            .entrySet()
            .stream()
            .sorted(Map.Entry.comparingByKey())
            .collect(Collectors.toMap(e -> Integer.parseInt(e.getKey().toString()),
                    Map.Entry::getValue,
                    (a, b) -> {
                        throw new AssertionError();
                    },
                    LinkedHashMap::new));
}

조정 "%.2f" 부동 소수점 정밀도를 설정합니다. 그 결과:

{2011=50.0, 2014=25.0, 2017=25.0}

주어진 책의 50%(2/4)가 2011년에 출판되었고, 25%(1/4)가 2014년에 출판되었고 25%(1/4)가 2017년에 출판되었습니다. 이 결과의 형식을 다르게 지정하고 정규화하려면 어떻게 해야 할까요? 범위 0..1?

Java에서 컬렉션의 정규화된(백분율) 분포 계산

백분율을 정규화하려면 0.0...100.0 범위 0..1 범위 – 우리는 단순히 적응할 것입니다 collectingAndThen() ~에게 전화 해 지원 수를 곱하다 100.0 컬렉션의 크기로 나누기 전에.

이전에는 Long 에 의해 반환된 개수 Collectors.counting() 암시적으로 double로 변환되었습니다(이중 값을 사용한 곱하기) – 그래서 이번에는 명시적으로 doubleValue()count:

    public static Map calculateDistributionNormalized(List books) {
        return books.stream()
            .collect(Collectors.groupingBy(Book::getPublishedYear,
                    Collectors.collectingAndThen(Collectors.counting(),
                            count -> (Double.parseDouble(String.format("%.4f", count.doubleValue() / books.size()))))))
            
            .entrySet()
            .stream()
            .sorted(comparing(e -> e.getKey()))
            .collect(Collectors.toMap(e -> Integer.parseInt(e.getKey().toString()),
                    Map.Entry::getValue,
                    (a, b) -> {
                        throw new AssertionError();
                    },
                    LinkedHashMap::new));
}

조정 "%.4f" 부동 소수점 정밀도를 설정합니다. 그 결과:

{2011=0.5, 2014=0.25, 2017=0.25}

컬렉션의 요소 수(빈도) 계산

마지막으로 – 단순히 컬렉션의 크기로 개수를 나누지 않음으로써 컬렉션의 요소 개수(모든 요소의 빈도)를 얻을 수 있습니다! 이것은 완전히 정규화되지 않은 카운트입니다.

   public static Map calculateDistributionCount(List books) {
        return books
            .stream()
            .collect(Collectors.groupingBy(Book::getPublishedYear,
                    Collectors.collectingAndThen(Collectors.counting(),
                            count -> (Integer.parseInt(String.format("%s", count.intValue()))))))
            
            .entrySet()
            .stream()
            .sorted(Map.Entry.comparingByKey())
            .collect(Collectors.toMap(e -> Integer.parseInt(e.getKey().toString()),
                    Map.Entry::getValue,
                    (a, b) -> {
                        throw new AssertionError();
                    },
                    LinkedHashMap::new));
}

결과 :

{2011=2, 2014=1, 2017=1}

실제로 2011년의 두 권의 책과 2014년과 2017년의 책이 각각 하나씩 있습니다.

결론

데이터 분포 계산은 데이터가 풍부한 애플리케이션에서 일반적인 작업이며 외부 라이브러리나 복잡한 코드를 사용할 필요가 없습니다. 함수형 프로그래밍 지원으로 Java는 컬렉션 작업을 쉽게 만들었습니다!

이 짧은 초안에서 컬렉션에 있는 모든 요소의 빈도 수를 계산하는 방법과 다음 사이의 백분율로 정규화된 분포 맵을 계산하는 방법을 살펴보았습니다. 01 만큼 잘 0100 자바에서.

타임 스탬프 :

더보기 스택카부스