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

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

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

ב-Codelab הזה תלמדו איך להפיק נתונים סטטיסטיים פרטיים עם צבירות פרטיות דיפרנציאליות מ-PipelineDP כדי להגן על אנשים פרטיות. PipelineDP היא framework של Python שמאפשרת להחיל פרטיות דיפרנציאלית על מערכי נתונים גדולים באמצעות מערכות עיבוד ברצף (batch processing), כמו Apache Spark ו-Apache Beam. מידע נוסף על חישוב נתונים סטטיסטיים פרטיים באופן דיפרנציאלי ב-Go זמין ב-Codelab של Privacy on Beam.

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

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

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

מה תלמדו

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

למה תזדקק?

  • אם אתם רוצים להריץ את Codelab בסביבה שלכם, אתם צריכים להתקין במחשב את גרסה 3.7 ואילך של Python.
  • אם אתם רוצים לעקוב אחרי ה-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 כי אתם מריצים את התוכנית הזו באופן מקומי ללא frameworks נוספות כמו Beam או Spark.

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

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

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

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

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

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

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

אם מריצים כמה צבירת נתונים עם אותה רשימה של מחיצות פלט לא ציבוריות באותו צינור עיבוד נתונים, אפשר ליצור את רשימת המחיצות פעם אחת באמצעות ה-method 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 אפשר לחשב כמה נתונים סטטיסטיים בו-זמנית, כל עוד הם חולקים את אותם פרמטרים במכונה של AggregateParams, שניתן לראות מאוחר יותר. לא רק שקל יותר לחשב מספר מדדים בפעם אחת, עדיף להשתמש בו גם מבחינת פרטיות.

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

אחד מהדברים שחשוב לזכור לגבי תקציב פרטיות הוא שהוא תקציב נוסף. אם אתם מפעילים צינור עיבוד נתונים עם epsilon אודיו ודלתא מילת מפתח מסוימת פעם אחת, אתם תוציאו תקציב (הסימן #### ). אם תפעילו אותו פעם שנייה, תצברו תקציב כולל של (2צות, 2 מכשירי ). באופן דומה, אם מחשבים מספר נתונים סטטיסטיים באמצעות שיטת NaiveBudgetAccountant ולאחר מכן מגדירים תקציב פרטיות של ≤ להודעה, תוציאו תקציב כולל של (20, 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

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

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

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

  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() כי מחשבים את סכום הצפיות במוצרים.

  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, ולכל צבירה יכולים להיות ערכים נפרדים. הם מחייבים את התרומה של המשתמש לכל מפתח.

הרעש שמתווסף לפלט מותאם לעומס (scaling) על ידי הפרמטרים 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.

מידע נוסף