חישוב של נתונים סטטיסטיים פרטיים באמצעות PipelineDP

1. לפני שמתחילים

יכול להיות שתחשבו שנתונים סטטיסטיים מצטברים לא חושפים מידע על האנשים שאליהם הם מתייחסים. עם זאת, יש הרבה דרכים שבהן תוקף יכול ללמוד מידע רגיש על אנשים מסטטיסטיקות מצטברות.

ב-codelab הזה תלמדו איך ליצור נתונים סטטיסטיים פרטיים עם צבירות פרטיות דיפרנציאליות מ-PipelineDP כדי להגן על הפרטיות של אנשים. ‫PipelineDP הוא פריימוורק של Python שמאפשר להחיל פרטיות דיפרנציאלית על מערכי נתונים גדולים באמצעות מערכות לעיבוד אצווה, כמו Apache Spark ו-Apache Beam. מידע נוסף על חישוב נתונים סטטיסטיים עם פרטיות דיפרנציאלית ב-Go זמין ב-codelab בנושא פרטיות ב-Beam.

פרטי פירושו שהפלט נוצר באופן שלא חושף מידע פרטי על האנשים שכלולים בנתונים. אפשר להשיג את התוצאה הזו באמצעות פרטיות דיפרנציאלית, מושג חזק של פרטיות שקשור לאנונימיזציה, שהוא תהליך של צבירת נתונים מכמה משתמשים כדי להגן על פרטיות המשתמשים. כל שיטות האנונימיזציה משתמשות בצבירה, אבל לא כל שיטות הצבירה משיגות אנונימיזציה. לעומת זאת, פרטיות דיפרנציאלית מספקת ערבויות מדידות לגבי דליפת מידע ופרטיות.

דרישות מוקדמות

  • היכרות עם Python
  • היכרות עם צבירת נתונים בסיסית
  • ניסיון ב-pandas,‏ Spark ו-Beam

מה תלמדו

  • מידע בסיסי על פרטיות דיפרנציאלית
  • איך מחשבים נתונים סטטיסטיים סיכומיים עם פרטיות דיפרנציאלית באמצעות PipelineDP
  • איך משנים את התוצאות באמצעות פרמטרים נוספים של פרטיות ושימושיות

הדרישות

  • אם רוצים להריץ את ה-codelab בסביבה שלכם, צריך להתקין במחשב את Python 3.7 ואילך.
  • אם רוצים לעבור על ה-codelab בלי סביבה משלכם, צריך לקבל גישה ל-Colaboratory.

‫2. הסבר על פרטיות דיפרנציאלית

כדי להבין טוב יותר את הפרטיות הדיפרנציאלית, כדאי לעיין בדוגמה הפשוטה הזו.

נניח שאתם עובדים במחלקת השיווק של קמעונאי אופנה באינטרנט, ואתם רוצים להבין אילו מהמוצרים שלכם הכי סביר שיימכרו.

בתרשים הזה מוצגים המוצרים שהלקוחות הסתכלו עליהם קודם כשביקרו באתר של החנות: חולצות טי, סוודרים, גרביים או ג'ינסים. חולצות טי הן הפריט הכי פופולרי, וגרביים הן הפריט הכי פחות פופולרי.

ea813c698889a4c6.png

האפשרות הזו נראית שימושית, אבל יש מלכוד. אם רוצים לקחת בחשבון מידע נוסף, כמו אם הלקוחות ביצעו רכישה או איזה מוצר הם צפו בו שני, יש סיכון לחשיפת פרטים אישיים בנתונים.

מהתרשים הזה אפשר לראות שלקוח אחד בלבד התעניין בסוודר ואז ביצע רכישה:

b7c6f7f891778366.png

מנקודת מבט של פרטיות, זה לא אידיאלי. הסטטיסטיקות האנונימיות לא אמורות לחשוף תרומות של אנשים פרטיים, אז מה עושים? אתם מוסיפים רעש אקראי לתרשימי העמודות כדי להפוך אותם לקצת פחות מדויקים.

תרשים העמודות הזה לא מדויק לחלוטין, אבל הוא עדיין שימושי והוא לא חושף תרומות של אנשים פרטיים:

b55e8d7f99f6d574.gif

פרטיות דיפרנציאלית היא הוספה של כמות נכונה של רעש אקראי כדי להסתיר תרומות של משתמשים ספציפיים.

הדוגמה הזו היא פשוטה מדי. ההטמעה הנכונה של פרטיות דיפרנציאלית היא מורכבת יותר, ויש בה מספר דקויות לא צפויות. בדומה לקריפטוגרפיה, לא מומלץ ליצור הטמעה משלכם של פרטיות דיפרנציאלית. במקום זאת, אפשר להשתמש ב-PipelineDP.

‫3. הורדה והתקנה של PipelineDP

לא צריך להתקין את PipelineDP כדי לעבוד עם ה-Codelab הזה, כי כל הקוד והתרשימים הרלוונטיים מופיעים במסמך הזה.

כדי להפעיל את PipelineDP, מריצים אותו בעצמכם או משתמשים בו מאוחר יותר:

  • מורידים ומתקינים את PipelineDP:
pip install pipeline-dp

כדי להריץ את הדוגמה באמצעות Apache Beam:

  • מורידים ומתקינים את Apache Beam:
pip install apache_beam

אפשר למצוא את הקוד של ה-codelab הזה ואת מערך הנתונים בספרייה PipelineDP/examples/codelab/.

4. חישוב מדדי ההמרות לפי המוצר הראשון שהמשתמש צפה בו

נניח שאתם עובדים בחנות אופנה באינטרנט ואתם רוצים להבין אילו מקטגוריות המוצרים השונות שלכם מניבות את המספר הגבוה ביותר של המרות ואת ערך ההמרה הגבוה ביותר כשמציגים אותן ראשונות. אתם רוצים לשתף את המידע הזה עם סוכנות השיווק שלכם וגם עם צוותים פנימיים אחרים, אבל אתם רוצים למנוע דליפה של מידע על לקוחות ספציפיים.

כדי לחשב את מדדי ההמרות לפי המוצר הראשון שהמשתמש צפה בו באתר:

  1. בודקים את מערך הנתונים לדוגמה של ביקורים באתר בספרייה PipelineDP/examples/codelab/.

צילום המסך הזה הוא דוגמה למערך הנתונים. הוא מכיל את מזהה המשתמש, את המוצרים שהמשתמש צפה בהם, אם המבקר ביצע המרה ואם כן, מה ערך ההמרה.

user_id

product_view_0

product_view_1

product_view_2

product_view_3

product_view_4

has_conversion

conversion_value

0

ג'ינס

t_shirt

t_shirt

אין

אין

false

0.0

1

ג'ינס

t_shirt

ג'ינס

ג'אמפר

אין

false

0.0

2

t_shirt

ג'אמפר

t_shirt

t_shirt

אין

true

105.19

3

t_shirt

t_shirt

ג'ינס

אין

אין

false

0.0

4

t_shirt

גרביים

ג'ינס

ג'ינס

אין

false

0.0

המדדים שמעניינים אותך:

  • view_counts: מספר הפעמים שבהן המבקרים באתר שלכם רואים כל מוצר בפעם הראשונה.
  • total_conversion_value: הסכום הכולל של הכסף שהמבקרים מוציאים כשהם מבצעים המרה.
  • conversion_rate: שיעור ההמרה של המבקרים.
  1. יצירת המדדים באופן לא פרטי:
conversion_metrics = df.groupby(['product_view_0'
                               ])[['conversion_value', 'has_conversion']].agg({
                                   'conversion_value': [len, np.sum],
                                   'has_conversion': np.mean
                               })
conversion_metrics = conversion_metrics.rename(
   columns={
       'len': 'view_counts',
       'sum': 'total_conversion_value',
       'mean': 'conversion_rate'
   }).droplevel(
       0, axis=1)

כמו שלמדתם קודם, הנתונים הסטטיסטיים האלה יכולים לחשוף מידע על אנשים במערך הנתונים. לדוגמה, רק אדם אחד המיר אחרי שראה קודם סרטון מעבר. אם היו 22 צפיות, שיעור ההמרה הוא בערך 0.05. עכשיו צריך להפוך כל תרשים עמודות לתרשים פרטי.

  1. מגדירים את פרמטרים הפרטיות באמצעות המחלקה pipeline_dp.NaiveBudgetAccountant, ואז מציינים את הארגומנטים epsilon ו-delta שרוצים להשתמש בהם בניתוח.

אופן ההגדרה של הארגומנטים האלה תלוי בבעיה הספציפית שלכם. מידע נוסף על הפרמטרים האלה זמין במאמר בנושא אופציונלי: שינוי הפרמטרים של הפרטיות הדיפרנציאלית.

בקטע הקוד הזה נעשה שימוש בערכים לדוגמה:

budget_accountant = pipeline_dp.NaiveBudgetAccountant(
     total_epsilon=1, total_delta=1e-5)
  1. מאתחלים את המופע של LocalBackend:
ops = pipeline_dp.LocalBackend()

אפשר להשתמש במופע LocalBackend כי אתם מריצים את התוכנית הזו באופן מקומי בלי מסגרות נוספות, כמו Beam או Spark.

  1. מאתחלים את המופע של DPEngine:
dp_engine = pipeline_dp.DPEngine(budget_accountant, ops)

באמצעות המחלקה pipeline_dp.AggregateParams של PipelineDP, אפשר לציין פרמטרים נוספים שמשפיעים על יצירת הנתונים הסטטיסטיים הפרטיים.

params = pipeline_dp.AggregateParams(
     noise_kind=pipeline_dp.NoiseKind.LAPLACE,
     metrics=[pipeline_dp.Metrics.COUNT],
     max_partitions_contributed=1,
     max_contributions_per_partition=1)
  1. מציינים שרוצים לחשב את המדד count ולהשתמש בהתפלגות הרעש LAPLACE.
  2. מגדירים את הארגומנט max_partitions_contributed לערך 1.

הארגומנט הזה מגביל את מספר הביקורים השונים שמשתמש יכול לתרום. אתם מצפים שהמשתמשים יבקרו באתר פעם ביום, ולא משנה אם הם מבקרים בו כמה פעמים במהלך היום.

  1. מגדירים את הארגומנט max_contributions_per_partitions לערך 1.

הארגומנט הזה מציין כמה תרומות מבקר יחיד יכול לתת למחיצה ספציפית או לקטגוריית מוצרים במקרה הזה.

  1. יוצרים מופע data_extractor שמציין איפה נמצאים השדות privacy_id, partition ו-value.

הקוד אמור להיראות כמו קטע הקוד הזה:

def run_pipeline(data, ops):
 budget_accountant = pipeline_dp.NaiveBudgetAccountant(
     total_epsilon=1, total_delta=1e-5)

 dp_engine = pipeline_dp.DPEngine(budget_accountant, ops)

 params = pipeline_dp.AggregateParams(
     noise_kind=pipeline_dp.NoiseKind.LAPLACE,
     metrics=[pipeline_dp.Metrics.COUNT],
     max_partitions_contributed=1, # A single user can only contribute to one partition.
     max_contributions_per_partition=1, # For a single partition, only one contribution per user is used.
     )

 data_extractors = pipeline_dp.DataExtractors(
     privacy_id_extractor=lambda row: row.user_id,
     partition_extractor=lambda row: row.product_view_0
     value_extractor=lambda row: row.has_conversion)

 dp_result = dp_engine.aggregate(data, params, data_extractors)

 budget_accountant.compute_budgets()

 return dp_result
  1. מוסיפים את הקוד הזה כדי להפוך את Pandas DataFrame לרשימה של שורות שמהן אפשר לחשב ישירות נתונים סטטיסטיים עם פרטיות דיפרנציאלית:
rows = [index_row[1] for index_row in df.iterrows()]
dp_result_local = run_pipeline(rows, ops) # Returns generator
list(dp_result_local)

מעולה! חישבתם את הנתון הסטטיסטי הראשון שלכם עם פרטיות דיפרנציאלית.

בתרשים הזה מוצגת התוצאה של הספירה עם פרטיות דיפרנציאלית לצד הספירה ללא פרטיות שחישבתם קודם:

a5a25a00858219ab.png

תרשים העמודות שמתקבל כשמריצים את הקוד עשוי להיות שונה מזה שמוצג כאן, וזה בסדר. בגלל הרעש בפרטיות דיפרנציאלית, בכל פעם שמריצים את הקוד מתקבל תרשים עמודות שונה, אבל אפשר לראות שהם דומים לתרשים העמודות המקורי שלא מבוסס על פרטיות דיפרנציאלית.

חשוב לציין שמאוד חשוב להבטיח את הפרטיות, ולכן לא מומלץ להריץ את צינור הנתונים כמה פעמים. מידע נוסף מופיע במאמר בנושא חישוב של נתונים סטטיסטיים מרובים.

5. שימוש במחיצות ציבוריות

בקטע הקודם, יכול להיות ששמתם לב שהשמטתם את כל נתוני הביקורים במחיצה, כלומר את המבקרים שראו לראשונה גרביים באתר שלכם.

הסיבה לכך היא בחירת מחיצות או הגדרת סף, שלב חשוב להבטחת פרטיות דיפרנציאלית כשקיום מחיצות הפלט תלוי בנתוני המשתמשים עצמם. במקרים כאלה, עצם קיומה של מחיצה בפלט יכול לחשוף את קיומו של משתמש פרטי בנתונים. כדי לקבל מידע נוסף על הסיבות לכך שזו הפרה של הפרטיות, אפשר לקרוא את הפוסט הזה בבלוג. כדי למנוע את הפגיעה הזו בפרטיות, PipelineDP שומר רק מחיצות עם מספר מספיק של משתמשים.

אם רשימת מחיצות הפלט לא תלויה בנתוני משתמש פרטיים, לא צריך לבצע את שלב בחירת המחיצה. זה המצב בדוגמה שלכם, כי אתם יודעים את כל קטגוריות המוצרים האפשריות שהלקוח יכול לראות קודם.

כדי להשתמש במחיצות:

  1. יוצרים רשימה של המחיצות האפשריות:
public_partitions_products = ['jeans', 'jumper', 'socks', 't-shirt']
  1. מעבירים את הרשימה לפונקציה run_pipeline(), שמגדירה אותה כקלט נוסף למחלקה pipeline_dp.AggregateParams:
run_pipeline(
    rows, ops, total_delta=0, public_partitions=public_partitions_products)
  # Returns generator
params = pipeline_dp.AggregateParams(
     noise_kind=pipeline_dp.NoiseKind.LAPLACE,
     metrics=[pipeline_dp.Metrics.COUNT],
     max_partitions_contributed=1,
     max_contributions_per_partition=1,
     public_partitions=public_partitions_products)

אם משתמשים במחיצות ציבוריות וברעש LAPLACE, אפשר להגדיר את הארגומנט total_delta לערך 0.

עכשיו אפשר לראות בתוצאה שמוצגים נתונים לגבי כל המחיצות או המוצרים.

a4f6302c8efcd5da.png

מחיצות ציבוריות לא רק מאפשרות לכם לשמור יותר מחיצות, אלא גם מוסיפות בערך חצי מהרעש, כי אתם לא מבזבזים תקציב פרטיות על בחירת מחיצות, כך שההבדל בין הספירות הגולמיות לבין הספירות הפרטיות קטן יותר בהשוואה להרצה הקודמת.

יש שני דברים חשובים שצריך לזכור כשמשתמשים במחיצות ציבוריות:

  • חשוב להיזהר כשמפיקים את רשימת המחיצות מנתונים גולמיים. אם לא תעשו את זה בצורה ששומרת על פרטיות דיפרנציאלית, הצינור לא יספק יותר הבטחות לפרטיות דיפרנציאלית. מידע נוסף זמין במאמר בנושא מתקדם: יצירת מחיצות מנתונים.
  • אם אין נתונים בחלק מהמחיצות הציבוריות, צריך להוסיף רעש למחיצות האלה כדי לשמור על פרטיות דיפרנציאלית. לדוגמה, אם השתמשתם במוצר נוסף כמו מכנסיים, שלא מופיע במערך הנתונים או באתר שלכם, הוא עדיין נחשב לרעשי רקע והתוצאות עשויות להראות ביקורים במוצרים כשלא היו כאלה.

מתקדם: יצירת מחיצות מנתונים

אם מריצים כמה צבירות עם אותה רשימה של מחיצות פלט לא ציבוריות באותו צינור, אפשר לגזור את רשימת המחיצות פעם אחת באמצעות השיטה dp_engine.select_private_partitions() ולספק את המחיצות לכל צבירה כקלט public_partitions. השיטה הזו לא רק בטוחה מבחינת פרטיות, אלא גם מאפשרת להוסיף פחות רעשי רקע כי משתמשים בתקציב הפרטיות רק פעם אחת לבחירת המחיצה לכל הצינור.

def get_private_product_views(data, ops):
 """Obtains the list of product_views in a private manner.

   This does not calculate any private metrics; it merely obtains the list of
   product_views but does so while making sure the result is differentially private.
   """

 # Set the total privacy budget.
 budget_accountant = pipeline_dp.NaiveBudgetAccountant(
     total_epsilon=1, total_delta=1e-5)

 # Create a DPEngine instance.
 dp_engine = pipeline_dp.DPEngine(budget_accountant, ops)

 # Specify how to extract privacy_id, partition_key, and value from a   
 # single element.
 data_extractors = pipeline_dp.DataExtractors(
     partition_extractor=lambda row: row.product_view_0,
     privacy_id_extractor=lambda row: row.user_id)

 # Run aggregation.
 dp_result = dp_engine.select_partitions(
     data, pipeline_dp.SelectPrivatePartitionsParams(
       max_partitions_contributed=1),
     data_extractors=data_extractors)

 budget_accountant.compute_budgets()
 return dp_result

6. חישוב של כמה נתונים סטטיסטיים

אחרי שהבנתם איך PipelineDP עובד, אפשר לראות איך אפשר להשתמש בו לכמה תרחישי שימוש מתקדמים יותר. כמו שציינתי בהתחלה, אתה מתעניין בשלושה נתונים סטטיסטיים. בעזרת PipelineDP אפשר לחשב כמה נתונים סטטיסטיים בו-זמנית, כל עוד הם חולקים את אותם פרמטרים במופע AggregateParams, שיוצג בהמשך. השיטה הזו לא רק נקייה וקלה יותר לחישוב של כמה מדדים בבת אחת, אלא גם טובה יותר מבחינת פרטיות.

אם אתם זוכרים את הפרמטרים epsilon ו-delta שאתם מספקים למחלקה NaiveBudgetAccountant, הם מייצגים משהו שנקרא תקציב פרטיות, שהוא מדד לכמות הפרטים האישיים של המשתמשים שאתם חושפים מתוך הנתונים.

חשוב לזכור שהתקציב לפרטיות הוא מצטבר. אם מריצים צינור עיבוד נתונים עם אפסילון ε ודלתא δ מסוימים פעם אחת, מוציאים תקציב של (ε,δ). אם מפעילים פתרונות חכמים פעם שנייה, התקציב הכולל הוא (2ε, 2δ). באופן דומה, אם מחשבים כמה נתונים סטטיסטיים באמצעות שיטת NaiveBudgetAccountant וברצף תקציב פרטיות של ε,δ, התקציב הכולל שמוציאים הוא (2ε, 2δ). המשמעות היא שאתם פוגעים בהתחייבויות לפרטיות.

כדי לעקוף את הבעיה הזו, צריך להשתמש במופע NaiveBudgetAccountant יחיד עם התקציב הכולל שרוצים להשתמש בו כשצריך לחשב כמה נתונים סטטיסטיים על אותם נתונים. לאחר מכן צריך לציין את הערכים של epsilon ושל delta שרוצים להשתמש בהם לכל צבירה. בסופו של דבר, תקבלו את אותה התחייבות כוללת לשמירה על פרטיות, אבל ככל שהערכים של epsilon ו-delta גבוהים יותר עבור צבירה מסוימת, כך רמת הדיוק שלה גבוהה יותר.

כדי לראות את זה בפעולה, אפשר לחשב את הנתונים הסטטיסטיים של count, mean ו-sum.

אתם מחשבים נתונים סטטיסטיים על סמך שני מדדים שונים: מדד conversion_value, שמשמש להסקת כמות ההכנסה שנוצרה על סמך המוצר שהמשתמש צפה בו ראשון, ומדד has_conversion, שמשמש לחישוב מספר המבקרים באתר ושיעור ההמרה הממוצע.

לכל מדד צריך לציין בנפרד את הפרמטרים שמשמשים לחישוב הנתונים הסטטיסטיים הפרטיים. אתם מחלקים את תקציב הפרטיות בין שני המדדים. אתם מחשבים שני נתונים סטטיסטיים מהמדד has_conversion, ולכן אתם רוצים להקצות לו שני שלישים מהתקציב הראשוני, ולהקצות את השליש הנותר למדד conversion_value.

כדי לחשב כמה נתונים סטטיסטיים:

  1. מגדירים את רואה החשבון של תקציב הפרטיות עם הערכים הכוללים של epsilon ו-delta שרוצים להשתמש בהם בשלושת הנתונים הסטטיסטיים:
budget_accountant = pipeline_dp.NaiveBudgetAccountant(
     total_epsilon=1, total_delta=0)
  1. מפעילים את DPEngine כדי לחשב את המדדים:
 dp_engine = pipeline_dp.DPEngine(budget_accountant, ops)
  1. מציינים את הפרמטרים של המדד.
params_conversion_value_metrics = pipeline_dp.AggregateParams(
     noise_kind=pipeline_dp.NoiseKind.LAPLACE,
     metrics=[pipeline_dp.Metrics.SUM],
     max_partitions_contributed=1,
     max_contributions_per_partition=1,
     min_value=0,
     max_value=100,
     public_partitions=public_partitions,
     budget_weight=1/3)

הארגומנט האחרון מציין באופן אופציונלי את המשקל של תקציב הפרטיות. אפשר לתת לכולם את אותו משקל, אבל אתם רוצים להגדיר את הארגומנט הזה כשליש, כמו שהוסבר קודם.

אתם מגדירים גם את הארגומנטים min_value ו-max_value כדי לציין את הגבול התחתון והגבול העליון שחלים על ערך שמועבר על ידי יחידת פרטיות במחיצה. הפרמטרים האלה נדרשים כשרוצים לחשב סכום או ממוצע פרטיים. אתם לא מצפים לערכים שליליים, ולכן אפשר להניח ש-0 ו-100 הם גבולות סבירים.

  1. לחלץ את הנתונים הרלוונטיים ואז להעביר אותם לפונקציית הצבירה:
data_extractors_conversion_value_metrics = pipeline_dp.DataExtractors(
     privacy_id_extractor=lambda row: row.user_id,
     partition_extractor=lambda row: row.product_view_0,
     value_extractor=lambda row: row.conversion_value)

 dp_result_conversion_value_metrics = (
     dp_engine.aggregate(data, params_conversion_value_metrics,
         data_extractors_conversion_value_metrics))
  1. כדי לחשב את שני המדדים על סמך המשתנה has_conversion, פועלים לפי אותם השלבים:
params_conversion_rate_metrics = pipeline_dp.AggregateParams(
     noise_kind=pipeline_dp.NoiseKind.LAPLACE,
     metrics=[pipeline_dp.Metrics.COUNT, pipeline_dp.Metrics.MEAN],
     max_partitions_contributed=1,
     max_contributions_per_partition=1,
     min_value=0,
     max_value=1,
     public_partitions=public_partitions,
     budget_weight=2/3)

 data_extractors_conversion_rate_metrics = pipeline_dp.DataExtractors(
     privacy_id_extractor=lambda row: row.user_id,
     partition_extractor=lambda row: row.product_view_0,
     value_extractor=lambda row: row.has_conversion)

 dp_result_conversion_rate_metrics = (
     dp_engine.aggregate(data, params_conversion_rate_metrics,
         data_extractors_conversion_rate_metrics))

השינוי היחיד הוא במופע pipeline_dp.AggregateParams, שבו מגדירים עכשיו את mean ואת count כצבירות, ומקצים שני שלישים מהתקציב לפרטיות לחישוב הזה. כדי שיהיו לכם אותם גבולות תרומה לשני הנתונים הסטטיסטיים ולחשב אותם על בסיס אותו משתנה has_conversion, אתם יכולים לשלב אותם באותו מופע pipeline_dp.AggregateParams ולחשב אותם בו-זמנית.

  1. מבצעים קריאה ל-budget_accountant.compute_budgets():
budget_accountant.compute_budgets()

אתם יכולים לשרטט את כל שלושת הנתונים הסטטיסטיים הפרטיים בהשוואה לנתונים הסטטיסטיים המקוריים. בהתאם לרעש שנוסף, אפשר לראות שהתוצאות יכולות להיות מחוץ לטווח הסביר. במקרה הזה, שיעור ההמרה וערך ההמרה הכולל של המשתמשים שעוברים בין אתרים הם שליליים, כי הרעש שנוסף הוא סימטרי סביב אפס. כדי לבצע ניתוחים ועיבודים נוספים, מומלץ לא לבצע עיבוד ידני של הנתונים הסטטיסטיים הפרטיים. עם זאת, אם רוצים להוסיף את התרשימים האלה לדוח, אפשר פשוט להגדיר את הערך המינימלי לאפס לאחר מכן, בלי להפר את ההבטחות בנוגע לפרטיות.

cb1fc563f817eaf.png

7. הפעלת צינור העיבוד באמצעות Beam

כיום, עיבוד נתונים מחייב התמודדות עם כמויות עצומות של נתונים, עד כדי כך שאי אפשר לעבד אותם באופן מקומי. במקום זאת, אנשים רבים משתמשים במסגרות לעיבוד נתונים בקנה מידה גדול, כמו Beam או Spark, ומריצים את צינורות הנתונים שלהם בענן.

‫PipelineDP תומך ב-Beam וב-Spark עם שינויים קטנים בלבד בקוד.

כדי להריץ את צינור הנתונים באמצעות Beam עם private_beam API:

  1. מאתחלים משתנה runner ואז יוצרים צינור עיבוד נתונים שבו מחילים את פעולות הפרטיות על ייצוג Beam של rows:
runner = fn_api_runner.FnApiRunner()  # local runner

with beam.Pipeline(runner=runner) as pipeline:
   beam_data = pipeline | beam.Create(rows)
  1. יוצרים משתנה budget_accountant עם פרמטרים נדרשים של פרטיות:
budget_accountant = pipeline_dp.NaiveBudgetAccountant(
               total_epsilon=1, total_delta=0)
  1. יוצרים משתנה pcol, או אוסף פרטי, כדי להבטיח שכל צבירות הנתונים יתאימו לדרישות בנושא פרטיות שלכם:
pcol = beam_data | pbeam.MakePrivate(
                                 budget_accountant=budget_accountant,
                                 privacy_id_extractor=lambda 
                                                    row: row.user_id)
  1. מציינים את הפרמטרים של הצבירה הפרטית בכיתה המתאימה.

כאן משתמשים ב-pipeline_dp.aggregate_params.SumParams()class כי מחשבים את סכום הצפיות במוצר.

  1. מעבירים את פרמטרים הצבירה לשיטה pbeam.Sum כדי לחשב את הנתון הסטטיסטי:
dp_result = pcol | pbeam.Sum(params)
  1. בסופו של דבר, הקוד שלכם צריך להיראות כמו קטע הקוד הזה:
import pipeline_dp.private_beam as pbeam
runner = fn_api_runner.FnApiRunner()  # local runner

with beam.Pipeline(runner=runner) as pipeline:
   beam_data = pipeline | beam.Create(rows)
   budget_accountant = pipeline_dp.NaiveBudgetAccountant(
               total_epsilon=1, total_delta=0)

   # Create private collection.
   pcol = beam_data | pbeam.MakePrivate(
                              budget_accountant=budget_accountant,
                              privacy_id_extractor=lambda row:  
                                                         row.user_id)
   # Specify parameters.
   params = pipeline_dp.aggregate_params.SumParams(
     noise_kind=pipeline_dp.NoiseKind.LAPLACE,
     max_partitions_contributed=1,
     max_contributions_per_partition=1,
     min_value=0,
     max_value=100,
     public_partitions=public_partitions_product_views,
     partition_extractor=lambda row: row.product_view_0,
     value_extractor=lambda row:row.conversion_value)
   dp_result = pcol | pbeam.Sum(params)

   budget_accountant.compute_budgets()
   dp_result | beam.Map(print)

8. אופציונלי: שינוי הפרמטרים של הפרטיות והתועלת

ב-Codelab הזה הוזכרו כמה פרמטרים, כמו הפרמטרים epsilon, delta ו-max_partitions_contributed. אפשר לחלק אותם באופן כללי לשתי קטגוריות: פרמטרים של פרטיות ופרמטרים של שימושיות.

פרמטרים של פרטיות

הפרמטרים epsilon ו-delta משמשים לכימות הפרטיות שאתם מספקים באמצעות פרטיות דיפרנציאלית. במילים אחרות, הם מדד לכמות המידע שתוקף פוטנציאלי יכול להשיג על הנתונים מהפלט האנונימי. ככל שהערך של הפרמטרים גבוה יותר, כך התוקף מקבל יותר מידע על הנתונים, וזהו סיכון לפרטיות. לעומת זאת, ככל שהערך של הפרמטרים epsilon ו-delta נמוך יותר, כך צריך להוסיף יותר רעשי רקע לפלט כדי להפוך אותו לאנונימי, וכך צריך יותר משתמשים ייחודיים בכל מחיצה כדי לשמור אותם בפלט האנונימי. במקרה כזה, יש פשרה בין התועלת לבין הפרטיות.

ב-PipelineDP, צריך לציין את רמת הפרטיות הרצויה של הפלט האנונימי כשמגדירים את תקציב הפרטיות הכולל במופע NaiveBudgetAccountant. החיסרון הוא שאם רוצים שההבטחות בנוגע לפרטיות יתקיימו, צריך להשתמש במופע NaiveBudgetAccountant נפרד לכל צבירה או להריץ את צינור הנתונים כמה פעמים כדי להימנע משימוש יתר בתקציב.

מידע נוסף על פרטיות דיפרנציאלית ועל המשמעות של פרמטרים של פרטיות זמין ברשימת קריאה בנושא פרטיות דיפרנציאלית.

פרמטרים של כלי

פרמטרים של כלי השירות לא משפיעים על ההתחייבויות בנושא פרטיות, אבל הם משפיעים על הדיוק וכתוצאה מכך על התועלת של הפלט. הם מסופקים במופע AggregateParams ומשמשים לשינוי קנה המידה של הרעש שנוסף.

פרמטר השירות שמופיע במופע AggregateParams ורלוונטי לכל הצבירות הוא הפרמטר max_partitions_contributed. מחיצה מתאימה למפתח של הנתונים שמוחזרים על ידי פעולת הצבירה של PipelineDP, ולכן הפרמטר max_partitions_contributed מגביל את מספר ערכי המפתח השונים שמשתמש יכול לתרום לפלט. אם משתמש תורם למספר מפתחות שגדול מהערך של הפרמטר max_partitions_contributed, חלק מהתרומות מושמטות כדי שהתרומה תהיה בדיוק הערך של הפרמטר max_partitions_contributed.

באופן דומה, לרוב הצבירות יש פרמטר max_contributions_per_partition. הם מסופקים גם במופע AggregateParams, ולכל צבירה יכולים להיות ערכים נפרדים. הם מגבילים את התרומה של המשתמש לכל מפתח.

ההפרעה שנוספת לפלט מותאמת על ידי הפרמטרים max_partitions_contributed ו-max_contributions_per_partition, ולכן יש כאן פשרה: ערכים גדולים יותר שמוקצים לכל פרמטר פירושם שאתם שומרים יותר נתונים, אבל התוצאה תהיה עם יותר הפרעות.

חלק מהצבירות דורשות פרמטרים של min_value ו-max_value, שמציינים את הגבולות של התרומות של כל משתמש. אם משתמש תורם ערך נמוך מהערך שמוקצה לפרמטר min_value, הערך יוגדל לערך של הפרמטר. באופן דומה, אם משתמש תורם ערך גדול יותר מהערך של הפרמטר max_value, הערך יוקטן לערך של הפרמטר. כדי לשמור יותר מהערכים המקוריים, צריך לציין גבולות רחבים יותר. הרעש מותאם לגודל הגבולות, כך שגבולות גדולים יותר מאפשרים לשמור יותר נתונים, אבל התוצאה תהיה עם יותר רעש.

לבסוף, הפרמטר noise_kind תומך בשני מנגנוני רעש שונים ב-PipelineDP: רעש GAUSSIAN ורעש LAPLACE. LAPLACEההתפלגות הזו מספקת תועלת טובה יותר עם גבולות תרומה נמוכים, ולכן PipelineDP משתמש בה כברירת מחדל. עם זאת, אם רוצים להשתמש ברעש של התפלגות GAUSSIAN, אפשר לציין אותו במופע AggregateParams.

9. מזל טוב

מעולה! סיימתם את ה-codelab של PipelineDP ולמדתם הרבה על פרטיות דיפרנציאלית ועל PipelineDP.

מידע נוסף