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

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

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

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

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

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

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

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

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

สิ่งที่ต้องมี

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

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

ดูตัวอย่างง่ายๆ นี้เพื่อให้เข้าใจ Differential Privacy ได้ดียิ่งขึ้น

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

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

ea813c698889a4c6.png

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

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

b7c6f7f891778366.png

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

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

b55e8d7f99f6d574.gif

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

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

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

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

หากต้องการเล่นกับ PipelineDP ให้เรียกใช้เองหรือใช้ภายหลัง:

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

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

  • ดาวน์โหลดและติดตั้ง Apacheบีม
pip install apache_beam

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

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

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

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

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

ภาพหน้าจอนี้เป็นตัวอย่างของชุดข้อมูล ซึ่งประกอบด้วยรหัสผู้ใช้ ผลิตภัณฑ์ที่ผู้ใช้ดู ผู้เข้าชมทํา 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 หลังจากบุคคลนั้นเห็นนักกระโดดก่อน สำหรับการดู 22 ครั้ง อัตรา Conversion จะอยู่ที่ประมาณ 0.05 ตอนนี้คุณจะต้องเปลี่ยนแผนภูมิแท่งแต่ละรายการให้เป็นแบบส่วนตัว

  1. กำหนดพารามิเตอร์ความเป็นส่วนตัวด้วยคลาส pipeline_dp.NaiveBudgetAccountant แล้วระบุอาร์กิวเมนต์ epsilon และ delta ที่ต้องการใช้สำหรับการวิเคราะห์

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

ข้อมูลโค้ดนี้ใช้ค่าตัวอย่างดังนี้

budget_accountant = pipeline_dp.NaiveBudgetAccountant(
     total_epsilon=1, total_delta=1e-5)
  1. เริ่มต้นอินสแตนซ์ LocalBackend:
ops = pipeline_dp.LocalBackend()

คุณใช้อินสแตนซ์ LocalBackend ได้เนื่องจากเรียกใช้โปรแกรมนี้ในเครื่องโดยไม่ต้องใช้เฟรมเวิร์กเพิ่มเติม เช่นบีมหรือ 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 เป็นรายการแถวที่คุณสามารถคำนวณสถิติ Differentiated Private ได้โดยตรง
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. ใช้พาร์ติชันสาธารณะ

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

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

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

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

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

สิ่งสำคัญที่ควรคำนึงถึงเกี่ยวกับงบประมาณความเป็นส่วนตัวคืองบประมาณที่เพิ่มขึ้น หากคุณเรียกใช้ไปป์ไลน์ที่มี epsilon ÷ และ delta markup ที่เฉพาะเจาะจง 1 ครั้ง คุณจะใช้จ่ายงบประมาณ (File, ÷) หากคุณเรียกใช้เป็นครั้งที่ 2 คุณจะใช้จ่ายงบประมาณทั้งหมด (2สแปม, 2÷) ในทำนองเดียวกัน หากคุณคำนวณสถิติหลายรายการด้วยเมธอด NaiveBudgetAccountant และรวมงบประมาณด้านความเป็นส่วนตัวเท่ากับ ÷ กำไร ต่อกัน คุณจะต้องใช้งบประมาณรวม (2FE, 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 สำหรับการวิเคราะห์และประมวลผลเพิ่มเติม ขอแนะนำว่าไม่ควรประมวลผลสถิติส่วนตัวด้วยตนเองในภายหลัง แต่หากต้องการเพิ่มกราฟเหล่านั้นลงในรายงาน คุณก็ตั้งค่าขั้นต่ำเป็น 0 ได้ในภายหลังโดยไม่ละเมิดการรับประกันความเป็นส่วนตัว

cb1fc563f817eaf.png

7. เรียกใช้ไปป์ไลน์ด้วยบีม

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

PipelineDP รองรับบีมและ Spark ที่มีการเปลี่ยนแปลงโค้ดเพียงเล็กน้อย

วิธีเรียกใช้ไปป์ไลน์ด้วยบีมด้วย private_beam API

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

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

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

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับ Differential Privacy และความหมายของพารามิเตอร์ความเป็นส่วนตัวได้ที่เรื่องรออ่านเกี่ยวกับ Differential Privacy

พารามิเตอร์ยูทิลิตี

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

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

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

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