बीम पर निजता के ज़रिए निजी आंकड़ों का हिसाब लगाना

1. परिचय

आपको लग सकता है कि एग्रीगेट किए गए आंकड़े, उन लोगों के बारे में कोई भी जानकारी लीक नहीं करते जिनके डेटा से ये जुड़े हैं. हालांकि, ऐसे कई तरीके हैं जिनसे कोई हमलावर किसी डेटासेट में मौजूद किसी व्यक्ति के बारे में संवेदनशील जानकारी को इकट्ठा किए गए आंकड़ों से जान सकता है.

लोगों की सुरक्षा के लिए निजता के लिए, आप बीम पर प्राइवसी से डिफ़रेंशियल प्राइवेट एग्रीगेशन का इस्तेमाल करके निजी आंकड़े तैयार करने का तरीका जानेंगे. बीम पर निजता एक डिफ़रेंशियल प्राइवसी फ़्रेमवर्क है, जो Apache बीम के साथ काम करता है.

"निजी" का क्या मतलब है?

‘निजी' शब्द इस्तेमाल करते समय कोडलैब के इस हिस्से में, हमारा मतलब है कि आउटपुट इस तरह तैयार किया जाएगा कि उससे डेटा में मौजूद किसी व्यक्ति की निजी जानकारी किसी से लीक नहीं होगी. ऐसा करने के लिए हम डिफ़रेंशियल प्राइवसी का इस्तेमाल कर सकते हैं. यह निजता की पहचान छिपाने का सबसे मज़बूत तरीका है. पहचान छिपाना, उपयोगकर्ता की निजता को सुरक्षित रखने के लिए कई उपयोगकर्ताओं का डेटा इकट्ठा करने की प्रोसेस है. पहचान छिपाने के सभी तरीकों में एग्रीगेशन का इस्तेमाल किया जाता है. हालांकि, एग्रीगेशन के सभी तरीकों में पहचान छिपाई नहीं जाती. वहीं दूसरी ओर, डिफ़रेंशियल प्राइवसी, जानकारी के लीक होने और निजता से जुड़ी गारंटी देता है.

2. डिफ़रेंशियल प्राइवसी के बारे में खास जानकारी

डिफ़रेंशियल प्राइवसी को बेहतर तरीके से समझने के लिए, आइए एक आसान उदाहरण पर नज़र डालें.

यह बार चार्ट किसी खास शाम को किसी छोटे रेस्टोरेंट में मौजूद भीड़-भाड़ को दिखाता है. शाम 7 बजे बहुत से मेहमान आते हैं और रात 1 बजे रेस्टोरेंट पूरी तरह से खाली रहता है:

a43dbf3e2c6de596.png

यह काम का है!

कोई कैच किया गया है. जब कोई नया मेहमान आता है, तो बार चार्ट में यह जानकारी तुरंत दिखती है. चार्ट देखें: साफ़ तौर पर पता चल रहा है कि कोई नया मेहमान आया है और यह मेहमान करीब रात 1 बजे आया है:

bda96729e700a9dd.png

निजता के नज़रिए से यह सही नहीं है. असल में पहचान छिपाकर दिए गए आंकड़ों से व्यक्तिगत योगदान की जानकारी नहीं मिलनी चाहिए. इन दो चार्ट को एक साथ रखने से स्थिति और भी साफ़ हो जाती है: नारंगी बार चार्ट में एक और मेहमान आता है जो रात 1 बजे से रात 1 बजे तक आता है:

d562ddf799288894.png

यह अच्छी बात नहीं है. हम क्या करें?

हम रैंडम नॉइज़ जोड़कर बार चार्ट को थोड़ा सटीक बना देंगे!

नीचे दिए गए दो बार चार्ट देखें. हालांकि, ये पूरी तरह से सटीक नहीं होते, लेकिन ये फिर भी काम के होते हैं और इनसे व्यक्तिगत योगदान की जानकारी नहीं मिलती. बढ़िया!

838a0293cd4fcfe3.gif

डिफ़रेंशियल प्राइवसी का मतलब है कि अलग-अलग योगदानों को मास्क करने के लिए, गै़र-ज़रूरी डेटा का सही लेवल सही है.

हमारा विश्लेषण कुछ हद तक आसान बना दिया गया था. डिफ़रेंशियल प्राइवसी को सही तरीके से लागू करना ज़्यादा अहम है. इसमें इसे लागू करने से जुड़ी कई बारीकियां दिखती हैं. क्रिप्टोग्राफ़ी की तरह ही, डिफ़रेंशियल प्राइवसी को अपने हिसाब से लागू करना सही नहीं होगा. आप अपने स्वयं के समाधान को लागू करने के बजाय, बीम पर निजता का इस्तेमाल कर सकते हैं. अपनी डिफ़रेंशियल प्राइवसी का इस्तेमाल न करें!

इस कोडलैब में, हम आपको बताएंगे कि बीम पर निजता का इस्तेमाल करके डिफ़रेंशियली प्राइवेट विश्लेषण कैसे किया जाता है.

3. बीम पर निजता सेटिंग डाउनलोड हो रही है

कोडलैब का आसानी से पालन करने के लिए, आपको बीम पर निजता सेटिंग डाउनलोड करने की ज़रूरत नहीं है. ऐसा इसलिए, क्योंकि इस दस्तावेज़ में सभी ज़रूरी कोड और ग्राफ़ मौजूद हैं. हालांकि, अगर आपको कोड चलाने के लिए इसे डाउनलोड करना है, इसे खुद चलाना है या बाद में बीम पर निजता का इस्तेमाल करना है, तो यहां दिया गया तरीका अपनाएं.

ध्यान दें कि यह कोडलैब, लाइब्रेरी के 1.1.0 वर्शन के लिए है.

पहले, बीम पर निजता की सेटिंग डाउनलोड करें:

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/ डायरेक्ट्री में मौजूद है.

आपको अपने कंप्यूटर पर Basel को इंस्टॉल करना भी होगा. Bazu की वेबसाइट पर, अपने ऑपरेटिंग सिस्टम को इंस्टॉल करने से जुड़े निर्देश देखें.

4. हर घंटे होने वाली विज़िट की गिनती करना

मान लें कि आप एक रेस्टोरेंट के मालिक हैं और आपको अपने रेस्टोरेंट से जुड़े कुछ आंकड़े शेयर करने हैं. जैसे, रेस्टोरेंट में सबसे ज़्यादा समय आने के बारे में जानकारी देना. अच्छी बात यह है कि आपको डिफ़रेंशियल प्राइवसी और पहचान छिपाने के बारे में पता है. इसलिए, आपको यह काम इस तरह करना है जिससे आपकी वेबसाइट पर आने वाले किसी भी व्यक्ति की जानकारी लीक न हो.

इस उदाहरण के लिए कोड codelab/count.go में है.

चलिए, एक मॉक डेटासेट लोड करने से शुरुआत करते हैं जिसमें किसी सोमवार को आपके रेस्टोरेंट में आने वाले लोगों की संख्या की जानकारी होती है. इस कोडलैब के उद्देश्यों के लिए यह कोड दिलचस्प नहीं है, लेकिन आप इसके लिए codelab/main.go, codelab/utils.go और codelab/visit.go में कोड देख सकते हैं.

विज़िटर आईडी

समय डाला गया

बिताया गया समय (मिनट)

खर्च किया गया पैसा (यूरो)

1

सुबह 9:30:00 बजे

26

24

2

सुबह 11:54:00 बजे

53

17

3

दोपहर 1:05:00 बजे

81

33

आप पहले नीचे दिए गए कोड सैंपल में बीम का इस्तेमाल करके, अपने रेस्टोरेंट में आने-जाने के समय का एक गैर-निजी बार चार्ट बनाएंगे. 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()
}

इससे मौजूदा डायरेक्ट्री में count.png के तौर पर एक अच्छा बार चार्ट (bazel run codelab -- --example="count" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/count.csv --output_chart_file=$(pwd)/count.png चलाकर) बनता है:

a179766795d4e64a.png

अगला चरण है, अपने पाइपलाइन और बार चार्ट को निजी में बदलना. हम यह कार्रवाई इस तरह करते हैं.

PrivatePCollection<V> पाने के लिए, सबसे पहले MakePrivateFromStruct को PCollection<V> पर कॉल करें. इनपुट PCollection, स्ट्रक्चर के संग्रह से जुड़ा होना चाहिए. हमें MakePrivateFromStruct के इनपुट के तौर पर, PrivacySpec और idFieldPath डालना होगा.

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

PrivacySpec एक ऐसा स्ट्रक्चर है जिसमें डिफ़रेंशियल प्राइवसी पैरामीटर (epsilon और डेल्टा) होता है. हम डेटा की पहचान छिपाने के लिए इसका इस्तेमाल करते हैं. (अभी आपको इस बारे में चिंता करने की ज़रूरत नहीं है. अगर आपको इनके बारे में ज़्यादा जानना है, तो बाद में हमारे पास एक वैकल्पिक सेक्शन उपलब्ध है.)

idFieldPath, स्ट्रक्चर में उपयोगकर्ता आइडेंटिफ़ायर फ़ील्ड का पाथ है (हमारे मामले में Visit). यहां, वेबसाइट पर आने वाले लोगों का उपयोगकर्ता आइडेंटिफ़ायर, Visit का VisitorID फ़ील्ड है.

इसके बाद, हम stats.Count() के बजाय pbeam.Count() को कॉल करते हैं. pbeam.Count(), इनपुट के तौर पर CountParams स्ट्रक्चर लेता है. इसमें 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

ऐसा, बंटवारे के लिए चुने गए/थ्रेशोल्ड की वजह से होता है. यह एक अहम चरण है, जिससे डिफ़रेंशियल प्राइवसी गारंटी को पक्का किया जा सकता है, क्योंकि आउटपुट वाले सेगमेंट की मौजूदगी, उपयोगकर्ता के डेटा पर निर्भर करती है. ऐसा होने पर, आउटपुट में सिर्फ़ किसी उपयोगकर्ता के मौजूद होने से, डेटा में मौजूद किसी उपयोगकर्ता की मौजूदगी का पता चल सकता है. यह जानने के लिए कि यह निजता का उल्लंघन क्यों करता है, यह ब्लॉग पोस्ट देखें. इससे बचने के लिए, बीम पर निजता की सुविधा उन हिस्सों को ही सेव करती है जिनमें ज़रूरत के मुताबिक उपयोगकर्ता हों.

जब आउटपुट विभाजनों की सूची निजी उपयोगकर्ता डेटा पर निर्भर नहीं करती, यानी वे सार्वजनिक जानकारी होती हैं, तो हमें इस विभाजन चयन चरण की आवश्यकता नहीं होती. हमारे रेस्टोरेंट वाले उदाहरण में यही बात लागू होती है: हमें रेस्टोरेंट के काम के घंटे (9.00 से 21.00) पता है.

इस उदाहरण के लिए कोड codelab/public_partitions.go में है.

हम सिर्फ़ 9 से 21 के बीच के घंटों का PCollection बनाएंगे और उसे 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
}

इससे मौजूदा डायरेक्ट्री में mean.png के तौर पर एक अच्छा बार चार्ट (bazel run codelab -- --example="mean" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/mean.csv --output_chart_file=$(pwd)/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
}

इससे मौजूदा डायरेक्ट्री में sum.png के तौर पर एक अच्छा बार चार्ट (bazel run codelab -- --example="sum" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/sum.csv --output_chart_file=$(pwd)/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. एकाधिक आंकड़ों की गणना करना

ज़्यादातर मामलों में, हो सकता है कि आपकी एक ही तरह के डेटा पर एक से ज़्यादा आंकड़ों का हिसाब लगाने में दिलचस्पी हो. ये वैसे ही होते हैं जैसे आपने गिनती, माध्य, और योग को ध्यान में रखकर किया है. आम तौर पर, किसी एक बीम पाइपलाइन और एक बाइनरी में ऐसा करना ज़्यादा साफ़ और आसान होता है. आप ऐसा बीम पर निजता के साथ भी कर सकते हैं. अपने ट्रांसफ़ॉर्मेशन और कंप्यूटेशन को चलाने के लिए, एक पाइपलाइन लिखी जा सकती है. साथ ही, पूरी पाइपलाइन के लिए, एक ही PrivacySpec का इस्तेमाल किया जा सकता है.

एक PrivacySpec के साथ ऐसा करना न सिर्फ़ ज़्यादा सुविधाजनक है, बल्कि निजता के मामले में भी बेहतर है. अगर आपको याद है कि हम PrivacySpec को जो ऐपसिलॉन और डेल्टा पैरामीटर देते हैं, वे निजता बजट को दिखाते हैं. इससे पता चलता है कि आप जिस डेटा को लीक कर रहे हैं उसमें उपयोगकर्ताओं की निजता का कितना स्तर है.

निजता के लिए बजट के बारे में याद रखने वाली एक बात यह है कि यह अलग से जोड़ा जाता है: अगर एक बार में किसी खास एप्सिलॉन, आइडेंटिफ़ायर, डेल्टा वैल्यू के साथ पाइपलाइन चलाई जा रही है, तो इसका मतलब है कि आपको एक ही बार में (क्षेत्रफल में) का बजट खर्च करना होगा. अगर आप इसे दूसरी बार चलाते हैं, तो इसका मतलब है कि आपका कुल बजट (2 पेमेंट्स, 26) खर्च होगा. इसी तरह, अगर आप PrivacySpec (और लगातार निजता बजट) (,,, 2,) के साथ कई आंकड़ों का हिसाब लगाते हैं, तो इसका मतलब है कि आपका कुल बजट (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 है. कोई विभाजन उस PCollection की कुंजी से मेल खाता है, जो बीम एग्रीगेशन की किसी कार्रवाई, जैसे कि Count, SumPerKey वगैरह से आउटपुट के रूप में मिलती है. इसलिए, MaxPartitionsContributed तय करता है कि कोई उपयोगकर्ता, आउटपुट में कितनी अलग-अलग कुंजी वैल्यू में योगदान कर सकता है. अगर कोई उपयोगकर्ता दिए गए डेटा में MaxPartitionsContributed से ज़्यादा कुंजियों का योगदान करती है, तो उसके कुछ योगदान छोड़ दिए जाएंगे, ताकि वह ठीक MaxPartitionsContributed कुंजियों के योगदान में योगदान दे सके.

MaxPartitionsContributed की तरह ही, ज़्यादातर एग्रीगेशन में MaxContributionsPerPartition पैरामीटर होता है. ये Params स्ट्रक्चर में दिए जाते हैं और हर एग्रीगेशन के लिए अलग-अलग वैल्यू हो सकती हैं. MaxPartitionsContributed के उलट, MaxContributionsPerPartition हर कुंजी के लिए उपयोगकर्ता के योगदान को सीमित करता है. दूसरे शब्दों में कहें, तो उपयोगकर्ता हर कुंजी के लिए सिर्फ़ MaxContributionsPerPartition वैल्यू दे सकता है.

आउटपुट में ग़ैर-ज़रूरी आवाज़ें कम करने के लिए, MaxPartitionsContributed और MaxContributionsPerPartition का इस्तेमाल किया जाता है. इसलिए, आपको एक फ़ायदा मिलता है: MaxPartitionsContributed और MaxContributionsPerPartition का साइज़ ज़्यादा होने का मतलब है कि ज़्यादा डेटा मिलेगा, लेकिन नतीजे में आपको ज़्यादा शोर मिलेगा.

कुछ एग्रीगेशन के लिए MinValue और MaxValue की ज़रूरत होती है. ये हर उपयोगकर्ता के योगदान की सीमाएं तय करती हैं. अगर कोई उपयोगकर्ता, MinValue से कम वैल्यू का योगदान देता है, तो उस वैल्यू को MinValue तक सीमित कर दिया जाएगा. इसी तरह, अगर कोई उपयोगकर्ता MaxValue से बड़ी वैल्यू दिखाता है, तो उस वैल्यू को MaxValue तक सीमित कर दिया जाता है. इसका मतलब है कि ओरिजनल वैल्यू को ज़्यादा बनाए रखने के लिए, आपको बड़ी सीमाएं तय करनी होंगी. MaxPartitionsContributed और MaxContributionsPerPartition की तरह, नॉइज़ को बाउंड के साइज़ के हिसाब से स्केल किया जाता है. इसलिए, बड़े बाउंड का मतलब है कि आपके पास ज़्यादा डेटा रहेगा, लेकिन नतीजे में आपको ज़्यादा शोर मिलेगा.

आखिरी पैरामीटर के बारे में हम बात करेंगे, वह है NoiseKind. हम प्राइवसी ऑन बीम में, ग़ैर-ज़रूरी आवाज़ों को ट्रैक करने की दो अलग-अलग प्रक्रियाओं के साथ काम करते हैं: GaussianNoise और LaplaceNoise. दोनों के अपने फ़ायदे और खामियां हैं, लेकिन लाप्लास डिस्ट्रिब्यूशन की सुविधा, कम योगदान के साथ बेहतर सुविधाएं देती है. इसी वजह से, प्राइवसी ऑन बीम इसका इस्तेमाल डिफ़ॉल्ट रूप से करती है. हालांकि, अगर आपको गॉसियन डिस्ट्रिब्यूशन नॉइज़ का इस्तेमाल करना है, तो pbeam.GaussianNoise{} वैरिएबल के साथ Params उपलब्ध कराया जा सकता है.

10. खास जानकारी

बहुत बढ़िया! आपने बीम कोडलैब (कोड बनाना सीखना) में निजता से जुड़ी प्रक्रिया पूरी कर ली है. आपने बीम पर डिफ़रेंशियल प्राइवसी और प्राइवसी के बारे में बहुत कुछ सीखा है:

  • MakePrivateFromStruct को कॉल करके अपने PCollection को PrivatePCollection में बदला जा रहा है.
  • डिफ़रेंशियल प्राइवेट काउंट की वैल्यू को कैलकुलेट करने के लिए, Count का इस्तेमाल किया जा रहा है.
  • अलग-अलग निजी तरीकों का पता लगाने के लिए MeanPerKey का इस्तेमाल किया जा रहा है.
  • डिफ़रेंशियल प्राइवेट योग को कैलकुलेट करने के लिए, SumPerKey का इस्तेमाल किया जा रहा है.
  • एक पाइपलाइन में, सिंगल PrivacySpec से कई आंकड़े गिनना.
  • (ज़रूरी नहीं) PrivacySpec और एग्रीगेशन पैरामीटर (CountParams, MeanParams, SumParams) को पसंद के मुताबिक बनाना.

लेकिन, बीम पर निजता की मदद से कई और एग्रीगेशन (जैसे कि क्वांटाइल, अलग-अलग वैल्यू की गिनती) किए जा सकते हैं! इनके बारे में ज़्यादा जानने के लिए, GitHub रिपॉज़िटरी या godoc पर जाएं.

अगर आपके पास समय है, तो कृपया सर्वे में हिस्सा लेकर, कोडलैब के बारे में हमें सुझाव/राय दें या शिकायत करें.