คำนวณสถิติส่วนตัวด้วย PipelineDP

1. ก่อนเริ่มต้น

คุณอาจคิดว่าสถิติรวมไม่ได้รั่วไหลข้อมูลใดๆ เกี่ยวกับบุคคลที่เกี่ยวข้อง อย่างไรก็ตาม ผู้โจมตีสามารถเรียนรู้ข้อมูลที่ละเอียดอ่อนเกี่ยวกับบุคคลจากสถิติรวมได้หลายวิธี

ในโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีสร้างสถิติส่วนตัวด้วยการรวบรวมข้อมูลแบบ Differential Privacy จาก PipelineDP เพื่อปกป้องความเป็นส่วนตัวของบุคคล PipelineDP เป็นเฟรมเวิร์ก Python ที่ช่วยให้คุณใช้ความเป็นส่วนตัวเชิงอนุพันธ์กับชุดข้อมูลขนาดใหญ่ด้วยระบบการประมวลผลแบบกลุ่ม เช่น Apache Spark และ Apache Beam ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีคำนวณสถิติแบบส่วนตัวเชิงอนุพันธ์ใน Go ได้ที่ Codelab Privacy on Beam

ส่วนตัวหมายความว่าเอาต์พุตจะสร้างขึ้นในลักษณะที่ไม่รั่วไหลข้อมูลส่วนตัวเกี่ยวกับบุคคลในข้อมูล คุณสามารถบรรลุผลลัพธ์นี้ได้ผ่าน Differential Privacy ซึ่งเป็นแนวคิดด้านความเป็นส่วนตัวที่เข้มงวดของการลบข้อมูลระบุตัวบุคคล ซึ่งเป็นกระบวนการรวบรวมข้อมูลของผู้ใช้หลายรายเพื่อปกป้องความเป็นส่วนตัวของผู้ใช้ วิธีการลบข้อมูลระบุตัวบุคคลทั้งหมดใช้การรวบรวม แต่ไม่ใช่ทุกวิธีการรวบรวมที่จะลบข้อมูลระบุตัวบุคคลได้ ในทางกลับกัน ความเป็นส่วนตัวเชิงแตกต่างจะให้การรับประกันที่วัดผลได้เกี่ยวกับการรั่วไหลของข้อมูลและความเป็นส่วนตัว

ข้อกำหนดเบื้องต้น

  • คุ้นเคยกับ Python
  • มีความคุ้นเคยกับการรวมข้อมูลพื้นฐาน
  • มีประสบการณ์ในการใช้ pandas, Spark และ Beam

สิ่งที่คุณจะได้เรียนรู้

  • ข้อมูลพื้นฐานเกี่ยวกับ Differential Privacy
  • วิธีคำนวณสถิติสรุปแบบส่วนตัวเชิงอนุพันธ์ด้วย PipelineDP
  • วิธีปรับแต่งผลการค้นหาด้วยพารามิเตอร์ความเป็นส่วนตัวและยูทิลิตีเพิ่มเติม

สิ่งที่คุณต้องมี

  • หากต้องการเรียกใช้โค้ดแล็บในสภาพแวดล้อมของคุณเอง คุณต้องติดตั้ง Python 3.7 ขึ้นไปในคอมพิวเตอร์
  • หากต้องการทำตาม Codelab โดยไม่มีสภาพแวดล้อมของคุณเอง คุณต้องมีสิทธิ์เข้าถึง Colaboratory

2. ทำความเข้าใจ Differential Privacy

หากต้องการทำความเข้าใจความเป็นส่วนตัวเชิงแตกต่างให้ดียิ่งขึ้น ให้ดูตัวอย่างง่ายๆ นี้

ลองนึกภาพว่าคุณทำงานในแผนกการตลาดของผู้ค้าปลีกแฟชั่นออนไลน์ และต้องการทราบว่าผลิตภัณฑ์ใดมีแนวโน้มที่จะขายได้มากที่สุด

แผนภูมินี้แสดงผลิตภัณฑ์ที่ลูกค้าดูเป็นอันดับแรกเมื่อเข้าชมเว็บไซต์ของร้านค้า ได้แก่ เสื้อยืด เสื้อจัมเปอร์ ถุงเท้า หรือกางเกงยีนส์ เสื้อยืดเป็นสินค้ายอดนิยมมากที่สุด ในขณะที่ถุงเท้าเป็นสินค้ายอดนิยมน้อยที่สุด

ea813c698889a4c6.png

ดูเหมือนว่าจะมีประโยชน์ แต่ก็มีข้อควรระวัง เมื่อต้องการพิจารณาข้อมูลเพิ่มเติม เช่น ลูกค้าทำการซื้อหรือไม่ หรือผลิตภัณฑ์ใดที่ลูกค้าดูเป็นอันดับที่ 2 คุณก็เสี่ยงที่จะเปิดเผยข้อมูลส่วนบุคคลในข้อมูล

แผนภูมินี้แสดงให้เห็นว่ามีลูกค้าเพียงรายเดียวเท่านั้นที่ดูจัมเปอร์ก่อน แล้วจึงทำการซื้อจริง

b7c6f7f891778366.png

ซึ่งไม่ดีนักในมุมมองด้านความเป็นส่วนตัว สถิติที่ลบข้อมูลระบุตัวบุคคลออกไม่ควรเปิดเผยการมีส่วนร่วมของแต่ละบุคคล คุณจึงควรทำดังนี้ คุณเพิ่มสัญญาณรบกวนแบบสุ่มลงในแผนภูมิแท่งเพื่อให้มีความแม่นยำน้อยลงเล็กน้อย

แผนภูมิแท่งนี้อาจไม่แม่นยำนัก แต่ก็ยังมีประโยชน์และไม่ได้แสดงผลงานของแต่ละบุคคล

b55e8d7f99f6d574.gif

Differential Privacy คือการเพิ่มสัญญาณรบกวนแบบสุ่มในปริมาณที่เหมาะสมเพื่อปกปิดข้อมูลที่แต่ละคนมีส่วนร่วม

ตัวอย่างนี้เป็นเพียงการอธิบายแบบง่ายๆ การติดตั้งใช้งานความเป็นส่วนตัวเชิงอนุพันธ์อย่างเหมาะสมนั้นมีความซับซ้อนมากขึ้นและมาพร้อมกับความละเอียดในการติดตั้งใช้งานที่ไม่คาดคิดหลายประการ เช่นเดียวกับการเข้ารหัส การสร้างการใช้งานความเป็นส่วนตัวเชิงแตกต่างของคุณเองอาจไม่ใช่ความคิดที่ดี แต่คุณสามารถใช้ PipelineDP แทนได้

3. ดาวน์โหลดและติดตั้ง PipelineDP

คุณไม่จำเป็นต้องติดตั้ง PipelineDP เพื่อทำตาม Codelab นี้ เนื่องจากคุณจะเห็นโค้ดและกราฟที่เกี่ยวข้องทั้งหมดในเอกสารนี้

หากต้องการเล่นด้วย PipelineDP, เรียกใช้ด้วยตนเอง หรือใช้ในภายหลัง ให้ทำดังนี้

  • ดาวน์โหลดและติดตั้ง PipelineDP โดยทำดังนี้
pip install pipeline-dp

หากต้องการเรียกใช้ตัวอย่างโดยใช้ Apache Beam ให้ทำดังนี้

  • ดาวน์โหลดและติดตั้ง Apache Beam โดยทำดังนี้
pip install apache_beam

คุณดูโค้ดสำหรับ Codelab นี้และชุดข้อมูลได้ในPipelineDP/examples/codelab/ไดเรกทอรี

4. คำนวณเมตริก Conversion ต่อผลิตภัณฑ์แรกที่ดู

สมมติว่าคุณทำงานที่ร้านค้าปลีกแฟชั่นออนไลน์ และต้องการทราบว่าหมวดหมู่ผลิตภัณฑ์ใดที่สร้างจำนวนและมูลค่า Conversion สูงสุดเมื่อดูเป็นครั้งแรก คุณต้องการแชร์ข้อมูลนี้กับเอเจนซีการตลาดและทีมภายในอื่นๆ แต่ต้องการป้องกันการรั่วไหลของข้อมูลเกี่ยวกับลูกค้าแต่ละราย

วิธีคํานวณเมตริก Conversion ต่อผลิตภัณฑ์แรกที่ดูสําหรับเว็บไซต์

  1. ตรวจสอบชุดข้อมูลจำลองของการเข้าชมเว็บไซต์ในไดเรกทอรี PipelineDP/examples/codelab/

ภาพหน้าจอนี้เป็นตัวอย่างของชุดข้อมูล ซึ่งประกอบด้วยรหัสของผู้ใช้ ผลิตภัณฑ์ที่ผู้ใช้ดู ผู้เข้าชมทํา Conversion หรือไม่ และหากทํา Conversion มูลค่าของ Conversion นั้นคือเท่าใด

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

ไม่มี

ไม่มี

เท็จ

0.0

1

กางเกงยีนส์

t_shirt

กางเกงยีนส์

จัมเปอร์

ไม่มี

เท็จ

0.0

2

t_shirt

จัมเปอร์

t_shirt

t_shirt

ไม่มี

จริง

105.19

3

t_shirt

t_shirt

กางเกงยีนส์

ไม่มี

ไม่มี

เท็จ

0.0

4

t_shirt

ถุงเท้า

กางเกงยีนส์

กางเกงยีนส์

ไม่มี

เท็จ

0.0

คุณสนใจเมตริกต่อไปนี้

  • view_counts: จำนวนครั้งที่ผู้เข้าชมเว็บไซต์เห็นผลิตภัณฑ์แต่ละรายการเป็นครั้งแรก
  • total_conversion_value: จำนวนเงินทั้งหมดที่ผู้เข้าชมใช้จ่ายเมื่อทำ Conversion
  • conversion_rate: อัตราที่ผู้เข้าชมทำ Conversion
  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)

ดังที่ได้ทราบไปก่อนหน้านี้ สถิติเหล่านี้อาจเปิดเผยข้อมูลเกี่ยวกับบุคคลในชุดข้อมูลของคุณ เช่น มีผู้ทำ Conversion เพียง 1 รายหลังจากที่เห็นจัมเปอร์ก่อน สำหรับการดู 22 ครั้ง อัตรา Conversion จะอยู่ที่ประมาณ 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)

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

พาร์ติชันสาธารณะไม่เพียงช่วยให้คุณเก็บพาร์ติชันได้มากขึ้น แต่ยังเพิ่มสัญญาณรบกวนประมาณครึ่งหนึ่งด้วย เนื่องจากคุณไม่ต้องใช้งบประมาณด้านความเป็นส่วนตัวในการเลือกพาร์ติชัน ความแตกต่างระหว่างจำนวนดิบกับจำนวนส่วนตัวจึงน้อยกว่าการเรียกใช้ครั้งก่อนเล็กน้อย

เมื่อใช้พาร์ติชันสาธารณะ คุณควรคำนึงถึงสิ่งสำคัญ 2 ประการต่อไปนี้

  • โปรดระมัดระวังเมื่อได้รายการพาร์ติชันจากข้อมูลดิบ หากไม่ดำเนินการในลักษณะที่รักษาความเป็นส่วนตัวแบบ Differential Privacy ไปป์ไลน์จะไม่รับประกัน Differential Privacy อีกต่อไป ดูข้อมูลเพิ่มเติมได้ที่ขั้นสูง: สร้างพาร์ติชันจากข้อมูล
  • หากไม่มีข้อมูลสำหรับพาร์ติชันสาธารณะบางส่วน คุณต้องใช้ Noise กับพาร์ติชันเหล่านั้นเพื่อรักษาความเป็นส่วนตัวเชิงแตกต่าง เช่น หากคุณใช้ผลิตภัณฑ์เพิ่มเติมอย่างกางเกง ซึ่งไม่ได้อยู่ในชุดข้อมูลหรือบนเว็บไซต์ ก็ยังถือเป็นสัญญาณรบกวน และผลลัพธ์อาจแสดงการเข้าชมผลิตภัณฑ์บางอย่างเมื่อไม่มีการเข้าชม

ขั้นสูง: สร้างพาร์ติชันจากข้อมูล

หากเรียกใช้การรวมหลายรายการที่มีรายการพาร์ติชันเอาต์พุตที่ไม่ใช่แบบสาธารณะเดียวกันในไปป์ไลน์เดียวกัน คุณสามารถรับรายการพาร์ติชันได้ครั้งเดียวด้วยวิธี 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 แล้ว คุณจะเห็นวิธีใช้สำหรับกรณีการใช้งานขั้นสูงขึ้น ดังที่กล่าวไว้ตอนต้น คุณสนใจสถิติ 3 รายการ PipelineDP ช่วยให้คุณคำนวณสถิติหลายรายการได้พร้อมกันตราบใดที่สถิติดังกล่าวใช้พารามิเตอร์เดียวกันในAggregateParamsอินสแตนซ์ ซึ่งคุณจะเห็นในภายหลัง ไม่เพียงแต่จะสะอาดตาและคำนวณเมตริกหลายรายการได้ง่ายขึ้นในคราวเดียว แต่ยังดีกว่าในแง่ของความเป็นส่วนตัวด้วย

หากคุณจำพารามิเตอร์ epsilon และ delta ที่คุณระบุให้กับคลาส NaiveBudgetAccountant ได้ พารามิเตอร์ดังกล่าวจะแสดงถึงสิ่งที่เรียกว่างบประมาณความเป็นส่วนตัว ซึ่งเป็นตัววัดปริมาณความเป็นส่วนตัวของผู้ใช้ที่คุณรั่วไหลจากข้อมูล

สิ่งสำคัญที่ควรทราบเกี่ยวกับงบประมาณความเป็นส่วนตัวคือเป็นงบประมาณที่เพิ่มขึ้น หากเรียกใช้ไปป์ไลน์ที่มีค่า epsilon ε และ delta δ ที่เฉพาะเจาะจงเพียงครั้งเดียว คุณจะใช้งบประมาณ (ε,δ) หากเรียกใช้เป็นครั้งที่ 2 คุณจะใช้งบประมาณทั้งหมด (2ε, 2δ) ในทำนองเดียวกัน หากคุณคำนวณสถิติหลายรายการด้วยNaiveBudgetAccountantวิธีและมีงบประมาณความเป็นส่วนตัว ε,δ ติดต่อกัน คุณจะใช้งบประมาณทั้งหมด (2ε, 2δ) ซึ่งหมายความว่าคุณจะลดระดับการรับประกันความเป็นส่วนตัว

หากต้องการหลีกเลี่ยงปัญหานี้ คุณต้องใช้NaiveBudgetAccountantอินสแตนซ์เดียวที่มีงบประมาณรวมที่คุณต้องการใช้เมื่อต้องคำนวณสถิติหลายรายการในข้อมูลเดียวกัน จากนั้นคุณต้องระบุค่า epsilon และ delta ที่ต้องการใช้สำหรับการรวบรวมแต่ละรายการ ท้ายที่สุดแล้ว คุณจะได้รับการรับประกันความเป็นส่วนตัวโดยรวมเหมือนเดิม แต่ยิ่งการรวบรวมข้อมูลหนึ่งๆ มีค่า epsilon และ delta สูงเท่าใด ความแม่นยำก็จะยิ่งสูงขึ้นเท่านั้น

หากต้องการดูการทำงานจริง คุณสามารถคำนวณสถิติ count, mean และ sum ได้

คุณคํานวณสถิติโดยอิงตามเมตริก 2 รายการที่แตกต่างกัน ได้แก่ เมตริก conversion_value ซึ่งคุณใช้เพื่ออนุมานจํานวนรายได้ที่สร้างขึ้นโดยอิงตามผลิตภัณฑ์ที่ดูเป็นอันดับแรก และเมตริก has_conversion ซึ่งคุณใช้เพื่อคํานวณจํานวนผู้เข้าชมเว็บไซต์และอัตรา Conversion เฉลี่ย

สําหรับเมตริกแต่ละรายการ คุณต้องระบุพารามิเตอร์ที่แนะนําการคํานวณสถิติส่วนตัวแยกกัน คุณแบ่งงบประมาณความเป็นส่วนตัวระหว่างเมตริกทั้ง 2 รายการ คุณคำนวณสถิติ 2 รายการจากเมตริก has_conversion จึงต้องการจัดสรรงบประมาณเริ่มต้น 2 ใน 3 ให้กับเมตริกนี้ และจัดสรรอีก 1 ใน 3 ให้กับเมตริก conversion_value

วิธีคำนวณสถิติหลายรายการ

  1. ตั้งค่าผู้ดูแลบัญชีงบประมาณความเป็นส่วนตัวด้วยค่า epsilon และ delta ทั้งหมดที่คุณต้องการใช้ในสถิติทั้ง 3 รายการ
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)

อาร์กิวเมนต์สุดท้ายจะระบุน้ำหนักของงบประมาณความเป็นส่วนตัวโดยไม่บังคับ คุณอาจกำหนดน้ำหนักเท่ากันให้กับทุกรายการ แต่คุณต้องการตั้งค่าอาร์กิวเมนต์นี้เป็น 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. ทำตามขั้นตอนเดียวกันเพื่อคำนวณเมตริกทั้ง 2 รายการโดยอิงตามตัวแปร 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 เป็นการรวบรวม และกำหนดงบประมาณส่วนตัว 2 ใน 3 ให้กับการคำนวณนี้ เนื่องจากคุณต้องการให้ขอบเขตการมีส่วนร่วมเหมือนกันทั้งสถิติและคำนวณสถิติเหล่านั้นบนตัวแปร has_conversion เดียวกัน คุณจึงรวมสถิติเหล่านั้นไว้ในอินสแตนซ์ pipeline_dp.AggregateParams เดียวกันและคำนวณพร้อมกันได้

  1. เรียกใช้เมธอด budget_accountant.compute_budgets() ดังนี้
budget_accountant.compute_budgets()

คุณสามารถพล็อตสถิติส่วนตัวทั้ง 3 รายการเพื่อเปรียบเทียบกับสถิติเดิมได้ คุณจะเห็นว่าผลลัพธ์อาจอยู่นอกเหนือช่วงที่สมเหตุสมผลได้จริง ทั้งนี้ขึ้นอยู่กับสัญญาณรบกวนที่เพิ่มเข้ามา ในกรณีนี้ คุณจะเห็นอัตรา Conversion และมูลค่า Conversion รวมที่เป็นลบสำหรับผู้ที่เปลี่ยนเส้นทาง เนื่องจากสัญญาณรบกวนที่เพิ่มเข้ามานั้นสมมาตรกันรอบๆ ศูนย์ สำหรับการวิเคราะห์และการประมวลผลเพิ่มเติม ทางที่ดีไม่ควรประมวลผลสถิติส่วนตัวด้วยตนเอง แต่หากต้องการเพิ่มพล็อตเหล่านั้นลงในรายงาน คุณก็สามารถตั้งค่าขั้นต่ำเป็น 0 ได้ในภายหลังโดยไม่ละเมิดการรับประกันความเป็นส่วนตัว

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() เนื่องจากคุณคำนวณผลรวมของการดูผลิตภัณฑ์

  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. ไม่บังคับ: ปรับแต่งพารามิเตอร์ความเป็นส่วนตัวและยูทิลิตี

คุณได้เห็นพารามิเตอร์หลายรายการที่กล่าวถึงในโค้ดแล็บนี้ เช่น พารามิเตอร์ epsilon, delta และ max_partitions_contributed คุณแบ่งพารามิเตอร์ออกเป็น 2 หมวดหมู่ได้คร่าวๆ ได้แก่ พารามิเตอร์ความเป็นส่วนตัวและพารามิเตอร์ยูทิลิตี

พารามิเตอร์ความเป็นส่วนตัว

พารามิเตอร์ epsilon และ delta จะวัดความเป็นส่วนตัวที่คุณให้ด้วยความเป็นส่วนตัวแบบแตกต่าง กล่าวอย่างเจาะจงคือ ค่าเหล่านี้เป็นตัววัดปริมาณข้อมูลที่ผู้โจมตีที่อาจเกิดขึ้นสามารถได้รับเกี่ยวกับข้อมูลจากเอาต์พุตที่ไม่ระบุตัวบุคคล ยิ่งค่าของพารามิเตอร์สูงเท่าใด ผู้โจมตีก็จะได้รับข้อมูลเกี่ยวกับข้อมูลมากขึ้นเท่านั้น ซึ่งเป็นความเสี่ยงด้านความเป็นส่วนตัว ในทางกลับกัน ยิ่งค่าพารามิเตอร์ epsilon และ delta ต่ำเท่าใด คุณก็ยิ่งต้องเพิ่มสัญญาณรบกวนลงในเอาต์พุตเพื่อให้เป็นแบบไม่ระบุตัวตน และยิ่งต้องมีจำนวนผู้ใช้ที่ไม่ซ้ำกันมากขึ้นในแต่ละพาร์ติชันเพื่อให้ผู้ใช้เหล่านั้นอยู่ในเอาต์พุตที่ผ่านการปกปิดข้อมูล ในกรณีนี้ จะต้องเลือกระหว่างยูทิลิตีและความเป็นส่วนตัว

ใน PipelineDP คุณต้องระบุการรับประกันความเป็นส่วนตัวที่ต้องการของเอาต์พุตที่ลบข้อมูลระบุตัวบุคคลออกเมื่อตั้งค่า Privacy Budget ทั้งหมดในอินสแตนซ์ 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 รองรับกลไกการเพิ่มสัญญาณรบกวน 2 แบบใน PipelineDP ได้แก่ สัญญาณรบกวน GAUSSIAN และ LAPLACE LAPLACE การกระจายจะให้ยูทิลิตีที่ดีกว่าโดยมีขอบเขตการมีส่วนร่วมต่ำ ซึ่งเป็นเหตุผลที่ PipelineDP ใช้การกระจายนี้โดยค่าเริ่มต้น อย่างไรก็ตาม หากต้องการใช้GAUSSIANสัญญาณรบกวนการกระจาย คุณสามารถระบุได้ในอินสแตนซ์ AggregateParams

9. ขอแสดงความยินดี

เก่งมาก คุณทำ Codelab ของ PipelineDP เสร็จแล้วและได้เรียนรู้มากมายเกี่ยวกับ Differential Privacy และ PipelineDP

ดูข้อมูลเพิ่มเติม