বীমে গোপনীয়তার সাথে ব্যক্তিগত পরিসংখ্যান কম্পিউটিং

1. ভূমিকা

আপনি ভাবতে পারেন যে সামগ্রিক পরিসংখ্যান ব্যক্তিদের সম্পর্কে কোন তথ্য ফাঁস করে না যাদের পরিসংখ্যানটি গঠিত। যাইহোক, একটি সমষ্টিগত পরিসংখ্যান থেকে একজন আক্রমণকারী একটি ডেটাসেটে ব্যক্তি সম্পর্কে সংবেদনশীল তথ্য জানতে পারে এমন অনেক উপায় রয়েছে।

ব্যক্তিদের গোপনীয়তা রক্ষা করতে, আপনি শিখবেন কীভাবে বিম-এ গোপনীয়তা থেকে পৃথকভাবে ব্যক্তিগত সমষ্টি ব্যবহার করে ব্যক্তিগত পরিসংখ্যান তৈরি করতে হয়। বীমের গোপনীয়তা হল একটি ডিফারেনশিয়াল প্রাইভেসি ফ্রেমওয়ার্ক যা Apache Beam এর সাথে কাজ করে।

আমরা "ব্যক্তিগত" বলতে কি বুঝি?

এই কোডল্যাব জুড়ে 'প্রাইভেট' শব্দটি ব্যবহার করার সময়, আমরা বলতে চাই যে আউটপুটটি এমনভাবে তৈরি করা হয়েছে যা ডেটাতে থাকা ব্যক্তিদের সম্পর্কে কোনও ব্যক্তিগত তথ্য ফাঁস করে না। আমরা ডিফারেনশিয়াল গোপনীয়তা ব্যবহার করে এটি করতে পারি, বেনামীকরণের একটি শক্তিশালী গোপনীয়তা ধারণা। বেনামীকরণ হল ব্যবহারকারীর গোপনীয়তা রক্ষা করার জন্য একাধিক ব্যবহারকারী জুড়ে ডেটা একত্রিত করার প্রক্রিয়া। সমস্ত বেনামী পদ্ধতি একত্রীকরণ ব্যবহার করে কিন্তু সমস্ত একত্রীকরণ পদ্ধতি বেনামীকরণ অর্জন করে না। অন্যদিকে, ডিফারেনশিয়াল গোপনীয়তা তথ্য ফাঁস এবং গোপনীয়তা সম্পর্কিত পরিমাপযোগ্য গ্যারান্টি প্রদান করে।

2. ডিফারেনশিয়াল প্রাইভেসি ওভারভিউ

ডিফারেনশিয়াল গোপনীয়তা আরও ভালভাবে বোঝার জন্য, আসুন একটি সাধারণ উদাহরণ দেখি।

এই বার চার্ট একটি নির্দিষ্ট সন্ধ্যায় একটি ছোট রেস্টুরেন্টের ব্যস্ততা দেখায়। অনেক অতিথি সন্ধ্যা 7 টায় আসেন, এবং রেস্তোঁরা 1 টায় সম্পূর্ণ খালি হয়:

a43dbf3e2c6de596.png

এই দরকারী দেখায়!

একটা ক্যাচ আছে। যখন একজন নতুন অতিথি আসে , এই সত্যটি বার চার্ট দ্বারা অবিলম্বে প্রকাশিত হয়। চার্টে দেখুন: এটা পরিষ্কার যে একজন নতুন অতিথি এসেছেন, এবং এই অতিথি প্রায় সকাল 1টায় এসেছেন:

bda96729e700a9dd.png

এটি একটি গোপনীয়তা দৃষ্টিকোণ থেকে মহান নয়. একটি সত্যিকারের বেনামী পরিসংখ্যান ব্যক্তিগত অবদান প্রকাশ করা উচিত নয়. এই দুটি চার্টকে পাশাপাশি রাখলে এটি আরও স্পষ্ট হয়: কমলা বার চার্টে একজন অতিরিক্ত অতিথি রয়েছে যা ~1am এ এসেছে:

d562ddf799288894.png

আবার, যে মহান না. আমরা কি করব?

আমরা এলোমেলো শব্দ যোগ করে বার চার্টগুলিকে কিছুটা কম নির্ভুল করব!

নিচের দুটি বার চার্ট দেখুন। সম্পূর্ণ নির্ভুল না হলেও, তারা এখনও দরকারী, এবং তারা ব্যক্তিগত অবদান প্রকাশ করে না। চমৎকার!

838a0293cd4fcfe3.gif

ডিফারেনশিয়াল গোপনীয়তা ব্যক্তিগত অবদানগুলিকে মাস্ক করতে সঠিক পরিমাণে এলোমেলো শব্দ যোগ করছে

আমাদের বিশ্লেষণ কিছুটা অতি সরলীকৃত ছিল। ডিফারেনশিয়াল গোপনীয়তা সঠিকভাবে প্রয়োগ করা আরও জড়িত এবং বেশ কিছু অপ্রত্যাশিত বাস্তবায়নের সূক্ষ্মতা রয়েছে। ক্রিপ্টোগ্রাফির মতো, ডিফারেনশিয়াল গোপনীয়তার আপনার নিজস্ব বাস্তবায়ন তৈরি করা একটি দুর্দান্ত ধারণা নাও হতে পারে। আপনি আপনার নিজের সমাধান বাস্তবায়নের পরিবর্তে Beam-এ গোপনীয়তা ব্যবহার করতে পারেন। আপনার নিজস্ব ডিফারেনশিয়াল গোপনীয়তা রোল করবেন না!

এই কোডল্যাবে, আমরা দেখাব কীভাবে বিম-এ গোপনীয়তা ব্যবহার করে আলাদাভাবে ব্যক্তিগত বিশ্লেষণ করতে হয়।

3. Beam-এ গোপনীয়তা ডাউনলোড করা হচ্ছে

কোডল্যাব অনুসরণ করতে সক্ষম হওয়ার জন্য আপনাকে Beam-এ গোপনীয়তা ডাউনলোড করতে হবে না কারণ সমস্ত প্রাসঙ্গিক কোড এবং গ্রাফ এই নথিতে পাওয়া যাবে। যাইহোক, যদি আপনি কোডের সাথে খেলতে ডাউনলোড করতে চান, এটি নিজে চালান বা পরে Beam-এ গোপনীয়তা ব্যবহার করুন, নিচের ধাপগুলি অনুসরণ করে নির্দ্বিধায় তা করতে পারেন।

মনে রাখবেন যে এই কোডল্যাবটি লাইব্রেরির 1.1.0 সংস্করণের জন্য।

প্রথমে, Beam-এ গোপনীয়তা ডাউনলোড করুন:

https://github.com/google/differential-privacy/archive/refs/tags/v1.1.0.tar.gz

অথবা আপনি Github সংগ্রহস্থল ক্লোন করতে পারেন:

git clone --branch v1.1.0 https://github.com/google/differential-privacy.git

বীমের গোপনীয়তা শীর্ষ স্তরের privacy-on-beam/ ডিরেক্টরিতে রয়েছে৷

এই কোডল্যাব এবং ডেটাসেটের কোডটি privacy-on-beam/codelab/ ডিরেক্টরিতে রয়েছে।

এছাড়াও আপনার কম্পিউটারে ব্যাজেল ইনস্টল থাকতে হবে। Bazel ওয়েবসাইটে আপনার অপারেটিং সিস্টেমের জন্য ইনস্টলেশন নির্দেশাবলী খুঁজুন।

4. প্রতি ঘন্টায় কম্পিউটিং ভিজিট

কল্পনা করুন আপনি একজন রেস্তোরাঁর মালিক এবং আপনার রেস্তোরাঁ সম্পর্কে কিছু পরিসংখ্যান শেয়ার করতে চান, যেমন জনপ্রিয় দর্শনের সময় প্রকাশ করা৷ সৌভাগ্যক্রমে, আপনি ডিফারেনশিয়াল প্রাইভেসি এবং বেনামীকরণ সম্পর্কে জানেন, তাই আপনি এটি এমনভাবে করতে চান যাতে কোনও পৃথক ভিজিটর সম্পর্কে তথ্য ফাঁস না হয়।

এই উদাহরণের কোডটি codelab/count.go এ রয়েছে।

চলুন শুরু করা যাক একটি নির্দিষ্ট সোমবারে আপনার রেস্তোরাঁয় ভিজিট সম্বলিত একটি মক ডেটাসেট লোড করা। এই কোডল্যাবের উদ্দেশ্যে এটির জন্য কোডটি আকর্ষণীয় নয়, তবে আপনি কোডটি codelab/main.go , codelab/utils.go এবং codelab/visit.go এ দেখতে পারেন।

ভিজিটর আইডি

সময় প্রবেশ করেছে

সময় কাটানো (মিনিট)

অর্থ ব্যয় (ইউরো)

1

সকাল 9:30:00

26

24

2

11:54:00 AM

53

17

3

1:05:00 PM

81

33

আপনি প্রথমে নীচের কোড নমুনায় Beam ব্যবহার করে আপনার রেস্তোরাঁয় যাওয়ার সময়গুলির একটি নন-প্রাইভেট বার চার্ট তৈরি করবেন। Scope হল পাইপলাইনের একটি উপস্থাপনা, এবং ডেটাতে আমরা যে প্রতিটি নতুন অপারেশন করি তা Scope এ যোগ করা হয়। CountVisitsPerHour একটি Scope এবং ভিজিটের একটি সংগ্রহ নেয়, যা বিম-এ একটি PCollection হিসাবে উপস্থাপন করা হয়। এটি সংগ্রহে extractVisitHour ফাংশন প্রয়োগ করে প্রতিটি দর্শনের ঘন্টা বের করে। তারপর এটি প্রতিটি ঘন্টার ঘটনা গণনা করে এবং এটি ফেরত দেয়।

func CountVisitsPerHour(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("CountVisitsPerHour")
    visitHours := beam.ParDo(s, extractVisitHourFn, col)
    visitsPerHour := stats.Count(s, visitHours)
    return visitsPerHour
}

func extractVisitHourFn(v Visit) int {
    return v.TimeEntered.Hour()
}

এটি একটি চমৎকার বার চার্ট তৈরি করে ( bazel run codelab -- --example="count" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/count.csv --output_chart_file=$(pwd)/count.png ) বর্তমান ডিরেক্টরিতে count.png হিসাবে :

a179766795d4e64a.png

পরবর্তী ধাপ হল আপনার পাইপলাইন এবং আপনার বার চার্টকে একটি ব্যক্তিগত রূপে রূপান্তর করা। আমরা নিম্নরূপ এই কাজ.

প্রথমে, একটি PrivatePCollection<V> PCollection<V> <V>-এ MakePrivateFromStruct কল করুন। ইনপুট PCollection Collection structs এর একটি সংগ্রহ হতে হবে। আমাদের MakePrivateFromStruct এ ইনপুট হিসাবে একটি PrivacySpec এবং একটি idFieldPath ইনপুট করতে হবে।

spec := pbeam.NewPrivacySpec(epsilon, delta)
pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

PrivacySpec হল একটি কাঠামো যা ডিফারেনশিয়াল প্রাইভেসি প্যারামিটার (এপসিলন এবং ডেল্টা) ধারণ করে যা আমরা ডেটা বেনামী করতে ব্যবহার করতে চাই। (আপনাকে আপাতত সেগুলি নিয়ে চিন্তা করার দরকার নেই, যদি আপনি সেগুলি সম্পর্কে আরও জানতে চান তবে পরে আমাদের কাছে একটি ঐচ্ছিক বিভাগ রয়েছে৷)

idFieldPath হল struct-এর মধ্যে ব্যবহারকারী শনাক্তকারী ক্ষেত্রের পথ (আমাদের ক্ষেত্রে Visit )। এখানে, ভিজিটরদের ইউজার আইডেন্টিফায়ার হল Visit এর VisitorID ফিল্ড।

তারপর, আমরা stats.Count() এর পরিবর্তে pbeam.Count() কল করি, pbeam.Count() একটি CountParams struct ইনপুট হিসাবে নেয় যা MaxValue এর মতো পরামিতি ধারণ করে যা আউটপুটের নির্ভুলতাকে প্রভাবিত করে।

visitsPerHour := pbeam.Count(s, visitHours, pbeam.CountParams{
    // Visitors can visit the restaurant once (one hour) a day
    MaxPartitionsContributed: 1,
    // Visitors can visit the restaurant once within an hour
    MaxValue:                 1,
})

একইভাবে, MaxPartitionsContributed সীমাবদ্ধ করে যে একজন ব্যবহারকারী কত ভিন্ন ভিজিট ঘন্টা অবদান রাখতে পারে। আমরা আশা করি তারা দিনে সর্বোচ্চ একবার রেস্তোরাঁয় যাবে (অথবা তারা দিনে একাধিকবার এটি দেখতে গেলে আমাদের কিছু যায় আসে না), তাই আমরা এটিকেও 1-এ সেট করি। আমরা একটি ঐচ্ছিক বিভাগে এই পরামিতিগুলি সম্পর্কে আরও বিস্তারিতভাবে কথা বলব।

আমরা যে মানগুলি গণনা করছি তাতে একজন একক ব্যবহারকারী কতবার অবদান রাখতে পারে তা MaxValue সীমাবদ্ধ করে৷ এই বিশেষ ক্ষেত্রে, আমরা যে মানগুলি গণনা করছি তা হল পরিদর্শন ঘন্টা, এবং আমরা আশা করি যে একজন ব্যবহারকারী শুধুমাত্র একবার রেস্টুরেন্টে ভিজিট করবে (অথবা তারা প্রতি ঘন্টায় একাধিকবার ভিজিট করলে আমাদের কিছু যায় আসে না), তাই আমরা এই প্যারামিটারটিকে 1 এ সেট করি।

শেষ পর্যন্ত, আপনার কোড এই মত দেখাবে:

func PrivateCountVisitsPerHour(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("PrivateCountVisitsPerHour")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    spec := pbeam.NewPrivacySpec(epsilon, delta)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    visitHours := pbeam.ParDo(s, extractVisitHourFn, pCol)
    visitsPerHour := pbeam.Count(s, visitHours, pbeam.CountParams{
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Visitors can visit the restaurant once within an hour
        MaxValue:                 1,
    })
    return visitsPerHour
}

আমরা আলাদাভাবে ব্যক্তিগত পরিসংখ্যানের জন্য একটি অনুরূপ বার চার্ট ( count_dp.png ) দেখতে পাচ্ছি (পূর্ববর্তী কমান্ডটি অ-প্রাইভেট এবং প্রাইভেট পাইপলাইন উভয়ই চালায়):

d6a0ace1acd3c760.png

অভিনন্দন! আপনি আপনার প্রথম ভিন্নভাবে ব্যক্তিগত পরিসংখ্যান গণনা করেছেন!

আপনি কোডটি চালানোর সময় যে বার চার্টটি পাবেন তা এর থেকে আলাদা হতে পারে। ঠিক আছে। ডিফারেনশিয়াল গোপনীয়তার গোলমালের কারণে, আপনি প্রতিবার কোডটি চালানোর সময় একটি ভিন্ন বার চার্ট পাবেন, কিন্তু আপনি দেখতে পাচ্ছেন যে সেগুলি আমাদের কাছে থাকা আসল নন-প্রাইভেট বার চার্টের সাথে কমবেশি একই রকম।

অনুগ্রহ করে মনে রাখবেন যে গোপনীয়তার গ্যারান্টিগুলির জন্য পাইপলাইনটি একাধিকবার পুনরায় চালানো না করা খুবই গুরুত্বপূর্ণ (উদাহরণস্বরূপ, একটি ভাল-সুদর্শন বার চার্ট পেতে)। কেন আপনার পাইপলাইনগুলি পুনরায় চালানো উচিত নয় তার কারণ "কম্পিউটিং একাধিক পরিসংখ্যান" বিভাগে ব্যাখ্যা করা হয়েছে।

5. পাবলিক পার্টিশন ব্যবহার করা

পূর্ববর্তী বিভাগে, আপনি হয়তো লক্ষ্য করেছেন যে আমরা কিছু পার্টিশনের জন্য সমস্ত ভিজিট (ডেটা) বাদ দিয়েছি, অর্থাৎ ঘন্টা।

d7fbc5d86d91e54a.png

এটি পার্টিশন নির্বাচন/থ্রেশহোল্ডিংয়ের কারণে, ডিফারেনশিয়াল গোপনীয়তার গ্যারান্টি নিশ্চিত করার একটি গুরুত্বপূর্ণ পদক্ষেপ যখন আউটপুট পার্টিশনের অস্তিত্ব ব্যবহারকারীর ডেটার উপর নির্ভর করে। যখন এটি হয়, আউটপুটে একটি পার্টিশনের নিছক অস্তিত্ব ডেটাতে একজন স্বতন্ত্র ব্যবহারকারীর অস্তিত্বকে ফাঁস করতে পারে (এটি কেন গোপনীয়তা লঙ্ঘন করে তার ব্যাখ্যার জন্য এই ব্লগ পোস্টটি দেখুন)। এটি প্রতিরোধ করার জন্য, Beam-এ গোপনীয়তা শুধুমাত্র সেই পার্টিশনগুলিকে রাখে যেগুলিতে পর্যাপ্ত সংখ্যক ব্যবহারকারী রয়েছে।

যখন আউটপুট পার্টিশনের তালিকা ব্যক্তিগত ব্যবহারকারীর ডেটার উপর নির্ভর করে না, অর্থাৎ সেগুলি সর্বজনীন তথ্য, আমাদের এই পার্টিশন নির্বাচন পদক্ষেপের প্রয়োজন নেই। এটি আসলে আমাদের রেস্টুরেন্টের উদাহরণের ক্ষেত্রে: আমরা রেস্টুরেন্টের কাজের সময় জানি (9.00 থেকে 21.00)।

এই উদাহরণের কোডটি codelab/public_partitions.go এ রয়েছে।

আমরা কেবল 9 থেকে 21 (একচেটিয়া) ঘন্টার একটি PC সংগ্রহ তৈরি করব এবং CountParams PublicPartitions ক্ষেত্রে ইনপুট করব:

func PrivateCountVisitsPerHourWithPublicPartitions(s beam.Scope,
    col beam.PCollection) beam.PCollection {
    s = s.Scope("PrivateCountVisitsPerHourWithPublicPartitions")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    spec := pbeam.NewPrivacySpec(epsilon, /* delta */ 0)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    // Create a PCollection of output partitions, i.e. restaurant's work hours
    // (from 9 am till 9pm (exclusive)).
    hours := beam.CreateList(s, [12]int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})

    visitHours := pbeam.ParDo(s, extractVisitHourFn, pCol)
    visitsPerHour := pbeam.Count(s, visitHours, pbeam.CountParams{
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Visitors can visit the restaurant once within an hour
        MaxValue:                 1,
        // Visitors only visit during work hours
        PublicPartitions:         hours,
    })
    return visitsPerHour
}

মনে রাখবেন যে আপনি যদি পাবলিক পার্টিশন এবং ল্যাপ্লেস নয়েজ (ডিফল্ট) ব্যবহার করেন তবে ডেল্টা 0 এ সেট করা সম্ভব, যেমনটি উপরের ক্ষেত্রে।

যখন আমরা পাবলিক পার্টিশন দিয়ে পাইপলাইন চালাই ( bazel run codelab -- --example="public_partitions" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/public_partitions.csv --output_chart_file=$(pwd)/public_partitions.png ), আমরা পাই ( public_partitions_dp.png ):

7c950fbe99fec60a.png

আপনি দেখতে পাচ্ছেন, আমরা এখন 9, 10 এবং 16 পার্টিশনগুলি রাখি যা আমরা আগে পাবলিক পার্টিশন ছাড়াই ফেলেছিলাম।

শুধুমাত্র পাবলিক পার্টিশন ব্যবহার করলেই আপনি আরও বেশি পার্টিশন রাখতে পারবেন না বরং পার্টিশন নির্বাচনের জন্য কোনো প্রাইভেসি বাজেট যেমন এপসিলন এবং ডেল্টা খরচ না করার কারণে পাবলিক পার্টিশন ব্যবহার না করার তুলনায় এটি প্রতিটি পার্টিশনে প্রায় অর্ধেক শব্দ যোগ করে। এ কারণেই আগের রানের তুলনায় কাঁচা ও প্রাইভেট কাউন্টের পার্থক্য কিছুটা কম।

পাবলিক পার্টিশন ব্যবহার করার সময় দুটি গুরুত্বপূর্ণ বিষয় মাথায় রাখতে হবে:

  1. কাঁচা ডেটা থেকে পার্টিশনের তালিকা তৈরি করার সময় সতর্কতা অবলম্বন করুন: আপনি যদি এটি আলাদাভাবে ব্যক্তিগতভাবে না করেন, যেমন ব্যবহারকারীর ডেটাতে থাকা সমস্ত পার্টিশনের তালিকা পড়া, আপনার পাইপলাইন আর ডিফারেনশিয়াল গোপনীয়তার গ্যারান্টি দেয় না। কীভাবে এটি আলাদাভাবে ব্যক্তিগত উপায়ে করা যায় সে সম্পর্কে নীচের উন্নত বিভাগটি দেখুন।
  2. যদি কিছু পাবলিক পার্টিশনের জন্য কোন ডেটা (যেমন ভিজিট) না থাকে, তবে ডিফারেনশিয়াল গোপনীয়তা রক্ষা করার জন্য সেই পার্টিশনগুলিতে শব্দ প্রয়োগ করা হবে। উদাহরণস্বরূপ, যদি আমরা 0 এবং 24 এর মধ্যে ঘন্টা ব্যবহার করি (9 এবং 21 এর পরিবর্তে), সমস্ত ঘন্টা শব্দ হবে এবং কিছু না থাকলে কিছু পরিদর্শন দেখাতে পারে।

(উন্নত) ডেটা থেকে পার্টিশন তৈরি করা

আপনি যদি একই পাইপলাইনে অ-পাবলিক আউটপুট পার্টিশনের একই তালিকার সাথে একাধিক একত্রীকরণ চালাচ্ছেন, আপনি একবার SelectPartitions() ব্যবহার করে পার্টিশনের তালিকা পেতে পারেন এবং PublicPartition ইনপুট হিসাবে প্রতিটি একত্রে পার্টিশন সরবরাহ করতে পারেন। এটি শুধুমাত্র গোপনীয়তার দৃষ্টিকোণ থেকে নিরাপদ নয়, এটি আপনাকে সম্পূর্ণ পাইপলাইনের জন্য শুধুমাত্র একবার পার্টিশন নির্বাচনের গোপনীয়তা বাজেট ব্যবহার করার কারণে কম শব্দ যোগ করতে দেয়।

6. থাকার গড় দৈর্ঘ্য গণনা করা

এখন যেহেতু আমরা জানি কিভাবে আলাদাভাবে ব্যক্তিগত উপায়ে স্টাফ গণনা করা যায়, আসুন আমরা গণনার উপায়গুলি দেখি। আরও নির্দিষ্টভাবে, আমরা এখন দর্শকদের থাকার গড় দৈর্ঘ্য গণনা করব।

এই উদাহরণের কোডটি codelab/mean.go এ রয়েছে।

সাধারণত, থাকার সময়কালের একটি নন-প্রাইভেট গড় গণনা করতে, আমরা stats.MeanPerKey() ব্যবহার করব একটি প্রি-প্রসেসিং ধাপের সাথে যা ভিজিটের ইনকামিং PCollection কে PCollection<K,V> এ রূপান্তরিত করে যেখানে K হল ভিজিট আওয়ার এবং V দর্শক রেস্টুরেন্টে কাটানো সময়।

func MeanTimeSpent(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("MeanTimeSpent")
    hourToTimeSpent := beam.ParDo(s, extractVisitHourAndTimeSpentFn, col)
    meanTimeSpent := stats.MeanPerKey(s, hourToTimeSpent)
    return meanTimeSpent
}

func extractVisitHourAndTimeSpentFn(v Visit) (int, int) {
    return v.TimeEntered.Hour(), v.MinutesSpent
}

এটি একটি সুন্দর বার চার্ট তৈরি করে ( bazel run codelab -- --example="mean" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/mean.csv --output_chart_file=$(pwd)/mean.png ) বর্তমান ডিরেক্টরিতে mean.png হিসাবে :

bc2df28bf94b3721.png

এই ডিফারেনশিয়ালি প্রাইভেট করার জন্য, আমরা আবার আমাদের PCollection PrivatePCollection এ রূপান্তর করি এবং stats.MeanPerKey() pbeam.MeanPerKey() দিয়ে প্রতিস্থাপন করি। Count এর মতই, আমাদের কাছে MeanParams আছে যা কিছু পরামিতি ধারণ করে যেমন MinValue এবং MaxValue যা নির্ভুলতাকে প্রভাবিত করে। MinValue এবং MaxValue প্রতিটি কী-তে প্রতিটি ব্যবহারকারীর অবদানের জন্য আমাদের কাছে থাকা সীমার প্রতিনিধিত্ব করে।

meanTimeSpent := pbeam.MeanPerKey(s, hourToTimeSpent, pbeam.MeanParams{
    // Visitors can visit the restaurant once (one hour) a day
    MaxPartitionsContributed:     1,
    // Visitors can visit the restaurant once within an hour
    MaxContributionsPerPartition: 1,
    // Minimum time spent per user (in mins)
    MinValue:                     0,
    // Maximum time spent per user (in mins)
    MaxValue:                     60,
})

এই ক্ষেত্রে, প্রতিটি কী এক ঘন্টার প্রতিনিধিত্ব করে এবং মান হল দর্শকদের ব্যয় করা সময়। আমরা MinValue 0 এ সেট করেছি কারণ আমরা আশা করি না যে দর্শকরা রেস্টুরেন্টে 0 মিনিটের কম সময় কাটাবে। আমরা MaxValue 60-এ সেট করি, যার মানে যদি কোনো দর্শক 60 মিনিটের বেশি সময় ব্যয় করে, আমরা সেই ব্যবহারকারীর 60 মিনিটের মতো সময় ব্যয় করি।

শেষ পর্যন্ত, আপনার কোড এই মত দেখাবে:

func PrivateMeanTimeSpent(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("PrivateMeanTimeSpent")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    spec := pbeam.NewPrivacySpec(epsilon, /* delta */ 0)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    // Create a PCollection of output partitions, i.e. restaurant's work hours
    // (from 9 am till 9pm (exclusive)).
    hours := beam.CreateList(s, [12]int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})

    hourToTimeSpent := pbeam.ParDo(s, extractVisitHourAndTimeSpentFn, pCol)
    meanTimeSpent := pbeam.MeanPerKey(s, hourToTimeSpent, pbeam.MeanParams{
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed:     1,
        // Visitors can visit the restaurant once within an hour
        MaxContributionsPerPartition: 1,
        // Minimum time spent per user (in mins)
        MinValue:                     0,
        // Maximum time spent per user (in mins)
        MaxValue:                     60,
        // Visitors only visit during work hours
        PublicPartitions:             hours,
    })
    return meanTimeSpent
}

আমরা আলাদাভাবে ব্যক্তিগত পরিসংখ্যানের জন্য একটি অনুরূপ বার চার্ট ( mean_dp.png ) দেখতে পাচ্ছি (আগের কমান্ডটি নন-প্রাইভেট এবং প্রাইভেট পাইপলাইন উভয়ই চালায়):

e8ac6a9bf9792287.png

আবার, গণনার অনুরূপ, যেহেতু এটি একটি ভিন্নভাবে ব্যক্তিগত অপারেশন, আমরা প্রতিবার এটি চালানোর সময় ভিন্ন ফলাফল পাব। কিন্তু আপনি দেখতে পাচ্ছেন যে আলাদাভাবে ব্যক্তিগত থাকার সময়কাল প্রকৃত ফলাফল থেকে খুব বেশি দূরে নয়।

7. প্রতি ঘন্টায় রাজস্ব কম্পিউটিং

আরেকটি আকর্ষণীয় পরিসংখ্যান যা আমরা দেখতে পারি তা হল দিনের সময় প্রতি ঘণ্টায় আয়।

এই উদাহরণের কোডটি codelab/sum.go এ রয়েছে।

আবার, আমরা নন-প্রাইভেট সংস্করণ দিয়ে শুরু করব। আমাদের মক ডেটাসেটে কিছু প্রাক-প্রক্রিয়াকরণের মাধ্যমে, আমরা একটি PCollection<K,V> তৈরি করতে পারি যেখানে K হল ভিজিট আওয়ার এবং V হল রেস্তোরাঁয় দর্শকের খরচ করা অর্থ: প্রতি ঘণ্টায় একটি অ-ব্যক্তিগত আয় গণনা করতে, আমরা করতে পারি stats.SumPerKey() কল করে দর্শকদের খরচ করা সমস্ত অর্থের যোগফল মাত্র

func RevenuePerHour(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("RevenuePerHour")
    hourToMoneySpent := beam.ParDo(s, extractVisitHourAndMoneySpentFn, col)
    revenues := stats.SumPerKey(s, hourToMoneySpent)
    return revenues
}

func extractVisitHourAndMoneySpentFn(v Visit) (int, int) {
    return v.TimeEntered.Hour(), v.MoneySpent
}

এটি একটি সুন্দর বার চার্ট তৈরি করে ( bazel run codelab -- --example="sum" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/sum.csv --output_chart_file=$(pwd)/sum.png ) বর্তমান ডিরেক্টরিতে sum.png হিসাবে :

548619173fad0c9a.png

এই ডিফারেনশিয়ালি প্রাইভেট করার জন্য, আমরা আবার আমাদের PCollection PrivatePCollection এ রূপান্তর করি এবং stats.SumPerKey() pbeam.SumPerKey() দিয়ে প্রতিস্থাপন করি। Count এবং MeanPerKey এর মতই, আমাদের কাছে SumParams আছে যা কিছু পরামিতি ধরে রাখে যেমন MinValue এবং MaxValue যা নির্ভুলতাকে প্রভাবিত করে।

revenues := pbeam.SumPerKey(s, hourToMoneySpent, pbeam.SumParams{
    // Visitors can visit the restaurant once (one hour) a day
    MaxPartitionsContributed: 1,
    // Minimum money spent per user (in euros)
    MinValue:                 0,
    // Maximum money spent per user (in euros)
    MaxValue:                 40,
})

এই ক্ষেত্রে, MinValue এবং MaxValue প্রত্যেক দর্শক যে অর্থ ব্যয় করে তার জন্য আমাদের কাছে থাকা সীমার প্রতিনিধিত্ব করে। আমরা MinValue 0 এ সেট করেছি কারণ আমরা আশা করি না যে দর্শকরা রেস্টুরেন্টে 0 ইউরোর কম খরচ করবে। আমরা MaxValue 40 এ সেট করেছি, যার মানে যদি একজন দর্শক 40 ইউরোর বেশি খরচ করে, আমরা সেই ব্যবহারকারীর 40 ইউরো খরচ করার মতো কাজ করি।

শেষ পর্যন্ত, কোডটি এইরকম দেখাবে:

func PrivateRevenuePerHour(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("PrivateRevenuePerHour")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    spec := pbeam.NewPrivacySpec(epsilon, /* delta */ 0)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    // Create a PCollection of output partitions, i.e. restaurant's work hours
    // (from 9 am till 9pm (exclusive)).
    hours := beam.CreateList(s, [12]int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})

    hourToMoneySpent := pbeam.ParDo(s, extractVisitHourAndMoneySpentFn, pCol)
    revenues := pbeam.SumPerKey(s, hourToMoneySpent, pbeam.SumParams{
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Minimum money spent per user (in euros)
        MinValue:                 0,
        // Maximum money spent per user (in euros)
        MaxValue:                 40,
        // Visitors only visit during work hours
        PublicPartitions:         hours,
    })
    return revenues
}

আমরা একটি অনুরূপ বার চার্ট ( sum_dp.png ) দেখতে পাই ডিফারেনশিয়ালি প্রাইভেট পরিসংখ্যানের জন্য (পূর্ববর্তী কমান্ডটি নন-প্রাইভেট এবং প্রাইভেট পাইপলাইন উভয়ই চালায়):

46c375e874f3e7c4.png

আবার, গণনা এবং গড়ের অনুরূপ, যেহেতু এটি একটি ভিন্নভাবে ব্যক্তিগত অপারেশন, আমরা প্রতিবার এটি চালানোর সময় ভিন্ন ফলাফল পাব। কিন্তু আপনি দেখতে পাচ্ছেন যে ভিন্নভাবে ব্যক্তিগত ফলাফল প্রতি ঘণ্টায় প্রকৃত আয়ের খুব কাছাকাছি।

8. একাধিক পরিসংখ্যান গণনা করা

বেশিরভাগ সময়, আপনি একই অন্তর্নিহিত ডেটার উপর একাধিক পরিসংখ্যান গণনা করতে আগ্রহী হতে পারেন, আপনি গণনা, গড় এবং যোগফলের সাথে যা করেছেন তার অনুরূপ। একটি একক বীম পাইপলাইনে এবং একটি একক বাইনারিতে এটি করা সাধারণত পরিষ্কার এবং সহজ। আপনি Beam এ গোপনীয়তার সাথেও এটি করতে পারেন। আপনি আপনার রূপান্তর এবং গণনা চালানোর জন্য একটি একক পাইপলাইন লিখতে পারেন এবং পুরো পাইপলাইনের জন্য একটি একক PrivacySpec ব্যবহার করতে পারেন।

এটি শুধুমাত্র একটি একক PrivacySpec দিয়ে এটি করা আরও সুবিধাজনক নয়, এটি গোপনীয়তার ক্ষেত্রেও ভাল৷ আপনি যদি PrivacySpec এ সরবরাহ করা এপিসিলন এবং ডেল্টা প্যারামিটারগুলি মনে রাখেন, তাহলে তারা একটি গোপনীয়তা বাজেট বলে কিছু উপস্থাপন করে, যা আপনি যে অন্তর্নিহিত ডেটা ফাঁস করছেন তাতে ব্যবহারকারীদের কতটা গোপনীয়তা রয়েছে তার একটি পরিমাপ।

গোপনীয়তা বাজেট সম্পর্কে মনে রাখা একটি গুরুত্বপূর্ণ বিষয় হল এটি সংযোজনকারী: আপনি যদি একটি নির্দিষ্ট epsilon ε এবং delta δ দিয়ে একটি পাইপলাইন একবার চালান, তাহলে আপনি একটি (ε,δ) বাজেট ব্যয় করছেন। আপনি যদি এটি দ্বিতীয়বার চালান, তাহলে আপনি মোট বাজেট (2ε, 2δ) ব্যয় করবেন। একইভাবে, আপনি যদি (ε,δ) একটি PrivacySpec (এবং ধারাবাহিকভাবে একটি গোপনীয়তা বাজেট) দিয়ে একাধিক পরিসংখ্যান গণনা করেন, তাহলে আপনি মোট বাজেট (2ε, 2δ) ব্যয় করবেন। এর মানে হল যে আপনি গোপনীয়তার গ্যারান্টি ক্ষুন্ন করছেন।

এটিকে এড়ানোর জন্য, আপনি যখন একই অন্তর্নিহিত ডেটার উপর একাধিক পরিসংখ্যান গণনা করতে চান, তখন আপনি যে মোট বাজেট ব্যবহার করতে চান তার সাথে আপনাকে একটি একক PrivacySpec ব্যবহার করতে হবে। তারপরে আপনাকে প্রতিটি সমষ্টির জন্য আপনি যে এপিসিলন এবং ডেল্টা ব্যবহার করতে চান তা নির্দিষ্ট করতে হবে। শেষ পর্যন্ত, আপনি একই সামগ্রিক গোপনীয়তার গ্যারান্টি দিয়ে শেষ করতে যাচ্ছেন; কিন্তু উচ্চতর এপিসিলন এবং ডেল্টা একটি নির্দিষ্ট সমষ্টি, উচ্চ নির্ভুলতা থাকবে।

এটি কার্যকরভাবে দেখতে, আমরা একটি একক পাইপলাইনে আগে আলাদাভাবে গণনা করা তিনটি পরিসংখ্যান (গণনা, গড় এবং যোগফল) গণনা করতে পারি।

এই উদাহরণের কোডটি codelab/multiple.go এ রয়েছে। লক্ষ্য করুন কিভাবে আমরা মোট (ε,δ) বাজেটকে তিনটি সমষ্টির মধ্যে সমানভাবে ভাগ করছি:

func ComputeCountMeanSum(s beam.Scope, col beam.PCollection) (visitsPerHour, meanTimeSpent, revenues beam.PCollection) {
    s = s.Scope("ComputeCountMeanSum")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    // Budget is shared by count, mean and sum.
    spec := pbeam.NewPrivacySpec(epsilon, /* delta */ 0)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    // Create a PCollection of output partitions, i.e. restaurant's work hours
    // (from 9 am till 9pm (exclusive)).
    hours := beam.CreateList(s, [12]int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})

    visitHours := pbeam.ParDo(s, extractVisitHourFn, pCol)
    visitsPerHour = pbeam.Count(s, visitHours, pbeam.CountParams{
        Epsilon:                  epsilon / 3,
        Delta:                    0,
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Visitors can visit the restaurant once within an hour
        MaxValue:                 1,
        // Visitors only visit during work hours
        PublicPartitions:         hours,
    })

    hourToTimeSpent := pbeam.ParDo(s, extractVisitHourAndTimeSpentFn, pCol)
    meanTimeSpent = pbeam.MeanPerKey(s, hourToTimeSpent, pbeam.MeanParams{
        Epsilon:                      epsilon / 3,
        Delta:                        0,
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed:     1,
        // Visitors can visit the restaurant once within an hour
        MaxContributionsPerPartition: 1,
        // Minimum time spent per user (in mins)
        MinValue:                     0,
        // Maximum time spent per user (in mins)
        MaxValue:                     60,
        // Visitors only visit during work hours
        PublicPartitions:             hours,
    })

    hourToMoneySpent := pbeam.ParDo(s, extractVisitHourAndMoneySpentFn, pCol)
    revenues = pbeam.SumPerKey(s, hourToMoneySpent, pbeam.SumParams{
        Epsilon:                  epsilon / 3,
        Delta:                    0,
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Minimum money spent per user (in euros)
        MinValue:                 0,
        // Maximum money spent per user (in euros)
        MaxValue:                 40,
        // Visitors only visit during work hours
        PublicPartitions:         hours,
    })

    return visitsPerHour, meanTimeSpent, revenues
}

9. (ঐচ্ছিক) ডিফারেনশিয়াল প্রাইভেসি প্যারামিটারগুলিকে টুইক করা

আপনি এই কোডল্যাবে উল্লিখিত বেশ কয়েকটি পরামিতি দেখেছেন: epsilon, delta, maxPartitionsContributed, ইত্যাদি। আমরা তাদের মোটামুটিভাবে দুটি বিভাগে ভাগ করতে পারি: গোপনীয়তা পরামিতি এবং ইউটিলিটি প্যারামিটার।

গোপনীয়তা পরামিতি

এপসিলন এবং ডেল্টা হল প্যারামিটার যা আমরা ডিফারেনশিয়াল গোপনীয়তা ব্যবহার করে যে গোপনীয়তা প্রদান করছি তা পরিমাপ করে। আরও স্পষ্টভাবে, এপিসিলন এবং ডেল্টা হল একটি পরিমাপ যে একটি সম্ভাব্য আক্রমণকারী বেনামী আউটপুট দেখে অন্তর্নিহিত ডেটা সম্পর্কে কতটা তথ্য লাভ করে। উচ্চতর এপসিলন এবং ডেল্টা, আক্রমণকারী অন্তর্নিহিত ডেটা সম্পর্কে তত বেশি তথ্য লাভ করে, যা গোপনীয়তার ঝুঁকি।

অন্যদিকে, নিম্ন এপিসিলন এবং ডেল্টা হল, বেনামী হওয়ার জন্য আপনাকে আউটপুটে যত বেশি শব্দ যোগ করতে হবে, এবং সেই পার্টিশনটিকে বেনামী আউটপুটে রাখার জন্য প্রতিটি পার্টিশনে আপনার প্রয়োজন উচ্চ সংখ্যক অনন্য ব্যবহারকারী। সুতরাং, এখানে ইউটিলিটি এবং গোপনীয়তার মধ্যে একটি ট্রেডঅফ রয়েছে।

প্রাইভেসি অন বিম-এ, যখন আপনি PrivacySpec এ মোট গোপনীয়তা বাজেট নির্দিষ্ট করেন তখন আপনার বেনামী আউটপুটে আপনি যে গোপনীয়তার গ্যারান্টি চান সে সম্পর্কে আপনাকে চিন্তিত হতে হবে। সতর্কতা হল যে আপনি যদি আপনার গোপনীয়তার গ্যারান্টিগুলি ধরে রাখতে চান তবে প্রতিটি সমষ্টির জন্য একটি পৃথক PrivacySpec করে বা একাধিকবার পাইপলাইন চালিয়ে আপনার বাজেটের অতিরিক্ত ব্যবহার না করার বিষয়ে আপনাকে এই কোডল্যাবের পরামর্শ অনুসরণ করতে হবে।

ডিফারেনশিয়াল প্রাইভেসি এবং গোপনীয়তার পরামিতিগুলি কী বোঝায় সে সম্পর্কে আরও তথ্যের জন্য, আপনি সাহিত্যের দিকে নজর দিতে পারেন।

ইউটিলিটি প্যারামিটার

এগুলি এমন প্যারামিটার যা গোপনীয়তার গ্যারান্টিগুলিকে প্রভাবিত করে না (যতক্ষণ পর্যন্ত বীমে গোপনীয়তা ব্যবহার করার পরামর্শ সঠিকভাবে অনুসরণ করা হয়) তবে নির্ভুলতা এবং ফলস্বরূপ আউটপুটের উপযোগিতাকে প্রভাবিত করে। এগুলি প্রতিটি সমষ্টির Params স্ট্রাকটে প্রদান করা হয়, যেমন CountParams , SumParams , ইত্যাদি।

Params প্রদত্ত একটি ইউটিলিটি প্যারামিটার এবং সমস্ত সমষ্টির ক্ষেত্রে প্রযোজ্য হল MaxPartitionsContributed । একটি পার্টিশন একটি প্রাইভেসি অন বিম অ্যাগ্রিগেশন অপারেশন দ্বারা আউটপুট করা PC Collection-এর একটি কী-এর সাথে মিলে যায়, যেমন Count , SumPerKey ইত্যাদি। সুতরাং, MaxPartitionsContributed সীমাবদ্ধ করে যে কতগুলি স্বতন্ত্র কী মান ব্যবহারকারী আউটপুটে অবদান রাখতে পারে। যদি একজন ব্যবহারকারী অন্তর্নিহিত ডেটাতে MaxPartitionsContributed কীগুলির থেকে বেশি অবদান রাখেন, তাহলে তার কিছু অবদান বাদ দেওয়া হবে যাতে সে ঠিক MaxPartitionsContributed কীগুলিতে অবদান রাখে।

MaxPartitionsContributed এর মতই, বেশিরভাগ সমষ্টির একটি MaxContributionsPerPartition প্যারামিটার থাকে। এগুলি Params স্ট্রাকটে সরবরাহ করা হয় এবং প্রতিটি একত্রিতকরণের জন্য আলাদা মান থাকতে পারে। MaxPartitionsContributed এর বিপরীতে, MaxContributionsPerPartition প্রতিটি কী-এর জন্য ব্যবহারকারীর অবদানকে আবদ্ধ করে। অন্য কথায়, একজন ব্যবহারকারী প্রতিটি কী-এর জন্য শুধুমাত্র MaxContributionsPerPartition মানগুলিই অবদান রাখতে পারেন।

আউটপুটে যোগ করা নয়েজটি MaxPartitionsContributed এবং MaxContributionsPerPartition দ্বারা স্কেল করা হয়েছে, তাই এখানে একটি ট্রেডঅফ রয়েছে: Larger MaxPartitionsContributed এবং MaxContributionsPerPartition উভয়ের অর্থ হল আপনি আরও ডেটা রাখবেন, কিন্তু আপনি আরও গোলমালের ফলাফল পাবেন।

কিছু সমষ্টির প্রয়োজন MinValue এবং MaxValue . এগুলি প্রতিটি ব্যবহারকারীর অবদানের সীমা নির্দিষ্ট করে। যদি একজন ব্যবহারকারী MinValue এর থেকে কম একটি মান প্রদান করে, তাহলে সেই মানটি MinValue এ ক্ল্যাম্প করা হবে। একইভাবে, যদি একজন ব্যবহারকারী MaxValue এর থেকে বড় একটি মান প্রদান করে, তাহলে সেই মানটি MaxValue তে ক্ল্যাম্প করা হবে। এর মানে হল যে আরও বেশি মূল মান রাখতে, আপনাকে বড় সীমা নির্দিষ্ট করতে হবে। MaxPartitionsContributed এবং MaxContributionsPerPartition এর মতোই, গোলমাল সীমার আকার দ্বারা মাপানো হয়, তাই বড় সীমার মানে হল আপনি আরও ডেটা রাখবেন, কিন্তু আপনি আরও বেশি গোলমালের ফলাফল পাবেন।

আমরা যে শেষ প্যারামিটারের কথা বলব তা হল NoiseKind । আমরা প্রাইভেসি অন বিমে দুটি ভিন্ন নয়েজ মেকানিজম সমর্থন করি: GaussianNoise এবং LaplaceNoise । উভয়েরই তাদের সুবিধা এবং অসুবিধা রয়েছে তবে ল্যাপ্লেস ডিস্ট্রিবিউশন কম অবদানের সীমার সাথে আরও ভাল ইউটিলিটি দেয়, তাই প্রাইভেসি অন বিম এটি ডিফল্টরূপে ব্যবহার করে। যাইহোক, আপনি যদি একটি গাউসিয়ান ডিস্ট্রিবিউশন নয়েজ ব্যবহার করতে চান, তাহলে আপনি একটি pbeam.GaussianNoise{} ভেরিয়েবল সহ Params সরবরাহ করতে পারেন।

10. সারাংশ

দারুণ কাজ! আপনি Beam কোডল্যাবে গোপনীয়তা শেষ করেছেন। আপনি বিমে ডিফারেনশিয়াল গোপনীয়তা এবং গোপনীয়তা সম্পর্কে অনেক কিছু শিখেছেন:

  • MakePrivateFromStruct কল করে আপনার PCollection একটি PrivatePCollection পরিণত করুন।
  • পৃথকভাবে ব্যক্তিগত গণনা গণনা করতে Count ব্যবহার করে।
  • ভিন্নভাবে ব্যক্তিগত উপায়ে গণনা করতে MeanPerKey ব্যবহার করে।
  • SumPerKey ব্যবহার করে ভিন্নভাবে ব্যক্তিগত রাশি গণনা করা।
  • একটি একক পাইপলাইনে একক PrivacySpec সহ একাধিক পরিসংখ্যান গণনা করা।
  • (ঐচ্ছিক) PrivacySpec এবং একত্রীকরণ পরামিতি কাস্টমাইজ করা ( CountParams, MeanParams, SumParams )।

কিন্তু, আরও অনেক সমষ্টি রয়েছে (যেমন কোয়ান্টাইল, স্বতন্ত্র মান গণনা) আপনি Beam-এ গোপনীয়তার সাথে করতে পারেন! আপনি GitHub সংগ্রহস্থল বা godoc এ তাদের সম্পর্কে আরও জানতে পারেন।

আপনার কাছে সময় থাকলে, অনুগ্রহ করে একটি সমীক্ষা পূরণ করে কোডল্যাব সম্পর্কে আমাদের মতামত দিন।