Hitung Distribusi dari Koleksi di Jawa

Mengubah kumpulan angka (atau objek yang bidangnya ingin Anda periksa) menjadi distribusi angka tersebut adalah teknik statistik umum, dan digunakan dalam berbagai konteks dalam pelaporan dan aplikasi berbasis data.

Diberikan koleksi:

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

Anda dapat memeriksa distribusinya sebagai hitungan (frekuensi setiap elemen), dan menyimpan hasilnya di peta:

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

Atau kamu bisa menormalkan nilai berdasarkan jumlah total nilai โ€“ dengan demikian menyatakannya dalam persentase:

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

Atau bahkan nyatakan persentase ini dalam a 0..100 format alih-alih a 0..1 Format.

Dalam panduan ini, kita akan melihat bagaimana Anda bisa menghitung distribusi dari koleksi โ€“ baik menggunakan tipe primitif dan objek yang bidangnya mungkin ingin Anda laporkan dalam aplikasi Anda.

Dengan tambahan dukungan pemrograman fungsional di Java โ€“ menghitung distribusi lebih mudah dari sebelumnya. Kami akan bekerja dengan koleksi angka dan koleksi Books:

public class Book {

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

   
}

Hitung Distribusi Koleksi di Jawa

Pertama-tama mari kita lihat bagaimana Anda dapat menghitung distribusi untuk tipe primitif. Bekerja dengan objek hanya memungkinkan Anda untuk memanggil metode kustom dari kelas domain Anda untuk memberikan lebih banyak fleksibilitas dalam perhitungan.

Secara default, kami akan mewakili persentase sebagai ganda dari 0.00 untuk 100.00.

Jenis Primitif

Mari buat daftar bilangan bulat dan cetak distribusinya:

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

Distribusi dihitung dengan:

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()))))));
}

Metode ini menerima daftar dan mengalirkannya. Saat dialirkan, nilainya adalah dikelompokkan berdasarkan nilai integer mereka โ€“ dan nilainya adalah terhitung menggunakan Collectors.counting(), sebelum dikumpulkan menjadi Map di mana kunci mewakili nilai input dan ganda mewakili persentase mereka dalam distribusi.

Metode kunci di sini adalah collect() yang menerima dua kolektor. Kolektor kunci mengumpulkan hanya dengan mengelompokkan berdasarkan nilai kunci (elemen input). Pengumpul nilai mengumpulkan melalui collectingAndThen() metode, yang memungkinkan kita untuk menghitung nilai dan kemudian memformatnya dalam format lain, seperti count * 100.00 / list.size() yang memungkinkan kami mengekspresikan elemen yang dihitung dalam persentase:

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

Urutkan Distribusi berdasarkan Nilai atau Kunci

Saat membuat distribusi โ€“ Anda biasanya ingin mengurutkan nilai. Lebih sering daripada tidak, ini akan terjadi kunci. Jawa HashMaps tidak menjamin untuk mempertahankan urutan penyisipan, jadi kita harus menggunakan LinkedHashMap yang tidak. Selain itu, paling mudah untuk melakukan streaming ulang peta dan mengumpulkannya kembali sekarang karena ukurannya jauh lebih kecil dan jauh lebih mudah dikelola.

Operasi sebelumnya dapat dengan cepat menciutkan beberapa ribu catatan ke dalam peta kecil, tergantung pada jumlah kunci yang Anda hadapi, jadi streaming ulang tidak mahal:

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));
}

benda

Bagaimana ini bisa dilakukan untuk objek? Logika yang sama berlaku! Alih-alih fungsi mengidentifikasi (Integer::intValue), kami akan menggunakan bidang yang diinginkan โ€“ seperti tahun penerbitan buku kami. Mari kita buat beberapa buku, simpan dalam daftar dan kemudian hitung distribusi tahun penerbitannya:

Lihat panduan praktis dan praktis kami untuk mempelajari Git, dengan praktik terbaik, standar yang diterima industri, dan termasuk lembar contekan. Hentikan perintah Googling Git dan sebenarnya belajar itu!

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);

Mari kita hitung distribusi publishedYear bidang:

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));
}

Sesuaikan "%.2f" untuk mengatur presisi floating point. Ini menghasilkan:

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

50% dari buku yang diberikan (2/4) diterbitkan pada tahun 2011, 25% (1/4) diterbitkan pada tahun 2014 dan 25% (1/4) pada tahun 2017. Bagaimana jika Anda ingin memformat hasil ini secara berbeda, dan menormalkan kisaran di 0..1?

Hitung Distribusi Koleksi yang Dinormalisasi (Persentase) di Jawa

Untuk menormalkan persentase dari a 0.0...100.0 berkisar ke 0..1 jangkauan โ€“ kami hanya akan mengadaptasi collectingAndThen() panggilan ke tidak kalikan jumlahnya dengan 100.0 sebelum dibagi dengan ukuran koleksi.

Sebelumnya, the Long hitungan dikembalikan oleh Collectors.counting() secara implisit diubah menjadi ganda (perkalian dengan nilai ganda) โ€“ jadi kali ini, kita ingin secara eksplisit mendapatkan doubleValue() dari 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));
}

Sesuaikan "%.4f" untuk mengatur presisi floating point. Ini menghasilkan:

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

Hitung Jumlah Elemen (Frekuensi) Koleksi

Akhirnya โ€“ kita bisa mendapatkan jumlah elemen (frekuensi semua elemen) dalam koleksi hanya dengan tidak membagi hitungan dengan ukuran koleksi! Ini adalah hitungan yang sepenuhnya tidak dinormalisasi:

   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));
}

Ini menghasilkan:

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

Memang, ada dua buku dari 2011, dan masing-masing satu dari 2014 dan 2017.

Kesimpulan

Menghitung distribusi data adalah tugas umum dalam aplikasi kaya data, dan tidak memerlukan penggunaan pustaka eksternal atau kode kompleks. Dengan dukungan pemrograman fungsional, Java membuat bekerja dengan koleksi menjadi mudah!

Dalam draf singkat ini, kami telah melihat bagaimana Anda dapat menghitung jumlah frekuensi semua elemen dalam koleksi, serta cara menghitung peta distribusi yang dinormalisasi ke persentase antara 0 dan 1 dan juga 0 dan 100 di Jawa.

Stempel Waktu:

Lebih dari penyalahgunaan