حساب التوزيع من المجموعة في جافا

يعد تحويل مجموعة من الأرقام (أو الكائنات التي ترغب في فحصها) إلى توزيع لتلك الأرقام أسلوبًا إحصائيًا شائعًا، ويتم استخدامه في سياقات مختلفة في إعداد التقارير والتطبيقات المستندة إلى البيانات.

نظرا لجمع:

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;

   
}

حساب توزيع المجموعة في جافا

دعونا أولاً نلقي نظرة على كيفية حساب التوزيع للأنواع البدائية. يتيح لك العمل مع الكائنات ببساطة استدعاء أساليب مخصصة من فئات المجال الخاص بك لتوفير المزيد من المرونة في العمليات الحسابية.

افتراضيًا، سنقوم بتمثيل النسب المئوية على شكل نسبة مضاعفة 0.00 إلى 100.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 حيث تمثل المفاتيح قيم الإدخال والمضاعفات تمثل نسبها في التوزيع.

الأساليب الرئيسية هنا هي 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 ، مع أفضل الممارسات ، والمعايير المقبولة في الصناعة ، وورقة الغش المضمنة. توقف عن أوامر Googling 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() تم تحويله ضمنيًا إلى مزدوج (الضرب بقيمة مزدوجة) - لذلك هذه المرة، سنرغب في الحصول بشكل صريح على 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 العمل مع المجموعات أمرًا سهلاً!

في هذه المسودة القصيرة، ألقينا نظرة على كيفية حساب أعداد التكرارات لجميع العناصر في المجموعة، بالإضافة إلى كيفية حساب خرائط التوزيع التي تمت تسويتها إلى نسب مئوية بين 0 و 1 وأيضا 0 و 100 في جافا.

الطابع الزمني:

اكثر من ستاكابوز