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 ได้ดียิ่งขึ้น
สมมติว่าคุณทำงานในแผนกการตลาดของผู้ค้าปลีกสินค้าแฟชั่นออนไลน์และต้องการทราบว่าผลิตภัณฑ์ใดมีแนวโน้มที่จะขายมากที่สุด
แผนภูมินี้แสดงผลิตภัณฑ์ที่ลูกค้าดูเป็นอันดับแรกเมื่อเข้าชมเว็บไซต์ของร้าน ซึ่งได้แก่ เสื้อยืด จั๊มพ์ ถุงเท้า หรือกางเกงยีนส์ เสื้อยืดเป็นสินค้ายอดนิยม ขณะที่ถุงเท้าเป็นสินค้ายอดนิยมน้อยที่สุด
ดูเหมือนจะมีประโยชน์ แต่ก็มีบางอย่างนะ เมื่อคุณต้องการพิจารณาข้อมูลเพิ่มเติม เช่น ลูกค้าทำการซื้อหรือเคยดูผลิตภัณฑ์ใดเป็นลำดับที่ 2 คุณจึงเสี่ยงที่จะเปิดเผยตัวคนในข้อมูล
แผนภูมินี้แสดงให้เห็นว่าลูกค้าเพียงคนเดียวที่มองจั๊มพลางก่อนแล้วทำการซื้อจริง
เรื่องนี้ไม่ค่อยดีนักในแง่ความเป็นส่วนตัว สถิติที่ลบการระบุตัวบุคคลไม่ควรเปิดเผยการมีส่วนร่วมแต่ละรายการ แล้วต้องทำอย่างไร คุณเพิ่มสัญญาณรบกวนแบบสุ่มในแผนภูมิแท่งเพื่อทำให้แม่นยำน้อยลงเล็กน้อย
แผนภูมิแท่งนี้อาจจะไม่ได้แม่นยำทั้งหมด แต่ก็ยังคงมีประโยชน์และจะไม่แสดงการมีส่วนร่วมแต่ละรายการ
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 ต่อผลิตภัณฑ์แรกที่ดูสําหรับเว็บไซต์
- ตรวจสอบชุดข้อมูลจำลองการเข้าชมเว็บไซต์ในไดเรกทอรี
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
: จำนวนเงินทั้งหมดที่ผู้เข้าชมจ่ายเมื่อเกิด Conversionconversion_rate
: อัตราที่ผู้เข้าชมทำ Conversion
- สร้างเมตริกแบบไม่เป็นส่วนตัว
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 ตอนนี้คุณจะต้องเปลี่ยนแผนภูมิแท่งแต่ละรายการให้เป็นแบบส่วนตัว
- กำหนดพารามิเตอร์ความเป็นส่วนตัวด้วยคลาส
pipeline_dp.NaiveBudgetAccountant
แล้วระบุอาร์กิวเมนต์epsilon
และdelta
ที่ต้องการใช้สำหรับการวิเคราะห์
วิธีกำหนดอาร์กิวเมนต์เหล่านี้ขึ้นอยู่กับปัญหาเฉพาะของคุณ ดูข้อมูลเพิ่มเติมเกี่ยวกับพารามิเตอร์เหล่านี้ได้ในส่วนไม่บังคับ: ปรับแต่งพารามิเตอร์ Differential Privacy
ข้อมูลโค้ดนี้ใช้ค่าตัวอย่างดังนี้
budget_accountant = pipeline_dp.NaiveBudgetAccountant(
total_epsilon=1, total_delta=1e-5)
- เริ่มต้นอินสแตนซ์
LocalBackend
:
ops = pipeline_dp.LocalBackend()
คุณใช้อินสแตนซ์ LocalBackend
ได้เนื่องจากเรียกใช้โปรแกรมนี้ในเครื่องโดยไม่ต้องใช้เฟรมเวิร์กเพิ่มเติม เช่นบีมหรือ Spark
- เริ่มต้นอินสแตนซ์
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)
- ระบุว่าคุณต้องการคำนวณเมตริก
count
และใช้การกระจายสัญญาณรบกวนLAPLACE
- ตั้งค่าอาร์กิวเมนต์
max_partitions_contributed
เป็นค่า1
อาร์กิวเมนต์นี้จะจำกัดจำนวนการเข้าชมที่แตกต่างกันที่ผู้ใช้รายหนึ่งมีส่วนร่วมได้ คุณคาดหวังให้ผู้ใช้เข้าชมเว็บไซต์วันละครั้ง และไม่สนใจว่าผู้ใช้เข้าชมเว็บไซต์ดังกล่าวหลายครั้งตลอดทั้งวันหรือไม่
- ตั้งค่าอาร์กิวเมนต์
max_contributions_per_partitions
เป็นค่า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
- เพิ่มโค้ดนี้เพื่อเปลี่ยน 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)
ยินดีด้วย คุณได้คำนวณสถิติส่วนตัวที่แตกต่างกันเป็นครั้งแรก
แผนภูมินี้แสดงผลลัพธ์ของจำนวนส่วนตัวที่แตกต่าง ข้างจำนวนที่ไม่ใช่แบบส่วนบุคคลซึ่งคุณคำนวณไว้ก่อนหน้านี้
แผนภูมิแท่งที่คุณได้รับเมื่อเรียกใช้โค้ดอาจแตกต่างจากเวอร์ชันนี้ ซึ่งไม่เป็นไร เนื่องจากความแตกต่างเรื่องความเป็นส่วนตัว ทำให้คุณเห็นแผนภูมิแท่งที่แตกต่างกันทุกครั้งที่เรียกใช้โค้ด แต่คุณจะเห็นว่าคล้ายกับแผนภูมิแท่งเดิมที่ไม่เป็นส่วนตัว
โปรดทราบว่าการรับประกันความเป็นส่วนตัวจะต้องไม่เรียกใช้ไปป์ไลน์หลายครั้งเพื่อการรับประกันความเป็นส่วนตัว สำหรับข้อมูลเพิ่มเติม โปรดดู คำนวณสถิติหลายรายการ
5. ใช้พาร์ติชันสาธารณะ
ในส่วนก่อนหน้านี้ คุณอาจสังเกตเห็นว่าคุณได้ทิ้งข้อมูลการเข้าชมทั้งหมดของพาร์ติชัน ซึ่งก็คือผู้เข้าชมที่เห็นถุงเท้าบนเว็บไซต์ของคุณก่อน
ทั้งนี้เนื่องจากการเลือกพาร์ติชันหรือการกำหนดเกณฑ์ ซึ่งเป็นขั้นตอนสำคัญเพื่อรับประกัน Differential Privacy ในการรับประกันเมื่อพาร์ติชันเอาต์พุตที่มีอยู่ขึ้นอยู่กับข้อมูลผู้ใช้ ในกรณีนี้ การมีอยู่ของพาร์ติชันในเอาต์พุตอาจทำให้การมีอยู่ของผู้ใช้แต่ละรายในข้อมูลไม่ได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุที่การดําเนินการนี้ละเมิดความเป็นส่วนตัวได้ที่บล็อกโพสต์นี้ เพื่อป้องกันการละเมิดความเป็นส่วนตัวเช่นนี้ PipelineDP จะเก็บพาร์ติชันที่มีผู้ใช้จำนวนมากพอ
เมื่อรายการของพาร์ติชันเอาต์พุตไม่ได้ขึ้นอยู่กับข้อมูลผู้ใช้ส่วนตัว คุณไม่จำเป็นต้องทำตามขั้นตอนการเลือกพาร์ติชันนี้ นี่คือตัวอย่างของคุณเนื่องจากคุณทราบหมวดหมู่ผลิตภัณฑ์ทั้งหมดที่เป็นไปได้ซึ่งลูกค้าควรเห็นเป็นอันดับแรก
วิธีใช้พาร์ติชัน
- สร้างรายการพาร์ติชันที่เป็นไปได้ดังนี้
public_partitions_products = ['jeans', 'jumper', 'socks', 't-shirt']
- ส่งรายชื่อไปยังฟังก์ชัน
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
ได้
ตอนนี้คุณจะเห็นว่ามีการรายงานข้อมูลสำหรับพาร์ติชันหรือผลิตภัณฑ์ทั้งหมดแล้ว
พาร์ติชันสาธารณะไม่เพียงช่วยให้คุณเก็บพาร์ติชันได้มากขึ้น แต่ยังเพิ่มสัญญาณรบกวนได้ราวครึ่งหนึ่ง เนื่องจากคุณไม่ได้ใช้งบประมาณความเป็นส่วนตัวในการเลือกพาร์ติชัน ดังนั้นความแตกต่างระหว่างจำนวนดิบและจำนวนส่วนตัวจึงน้อยกว่าเมื่อเทียบกับการเรียกใช้ครั้งก่อนเล็กน้อย
มีสิ่งสำคัญ 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
วิธีคำนวณสถิติหลายรายการ
- สร้างบัญชีงบประมาณความเป็นส่วนตัวด้วยค่า
epsilon
และdelta
รวมที่คุณต้องการใช้ในสถิติ 3 รายการ ได้แก่
budget_accountant = pipeline_dp.NaiveBudgetAccountant(
total_epsilon=1, total_delta=0)
- เริ่มต้น
DPEngine
เพื่อคํานวณเมตริก ดังนี้
dp_engine = pipeline_dp.DPEngine(budget_accountant, ops)
- ระบุพารามิเตอร์สำหรับเมตริกนี้
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
เป็นขอบเขตที่สมเหตุสมผล
- แยกข้อมูลที่เกี่ยวข้องแล้วส่งไปยังฟังก์ชันการรวมข้อมูล โดยทำดังนี้
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))
- ทำตามขั้นตอนเดียวกันเพื่อคำนวณเมตริก 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
เดียวกันและคำนวณทั้งสองพร้อมๆ กัน
- เรียกเมธอด
budget_accountant.compute_budgets()
:
budget_accountant.compute_budgets()
คุณสามารถพล็อตสถิติส่วนตัวทั้ง 3 รายการโดยเปรียบเทียบกับสถิติเดิม ทั้งนี้ขึ้นอยู่กับสัญญาณรบกวนที่เพิ่มเข้าไป คุณจะเห็นว่าผลลัพธ์อาจอยู่นอกขอบเขตที่เป็นไปได้ ในกรณีนี้ คุณจะเห็นอัตรา Conversion ที่เป็นค่าลบและมูลค่า Conversion รวมสำหรับผู้กระโดด เนื่องจากสัญญาณรบกวนที่เพิ่มเข้าไปนั้นสมมาตรกับ 0 สำหรับการวิเคราะห์และประมวลผลเพิ่มเติม ขอแนะนำว่าไม่ควรประมวลผลสถิติส่วนตัวด้วยตนเองในภายหลัง แต่หากต้องการเพิ่มกราฟเหล่านั้นลงในรายงาน คุณก็ตั้งค่าขั้นต่ำเป็น 0 ได้ในภายหลังโดยไม่ละเมิดการรับประกันความเป็นส่วนตัว
7. เรียกใช้ไปป์ไลน์ด้วยบีม
ปัจจุบันการประมวลผลข้อมูลต้องการให้คุณจัดการกับข้อมูลจำนวนมาก มากเสียจนคุณไม่สามารถประมวลผลข้อมูลนั้นภายในเครื่องได้ แต่มีคนจำนวนมากใช้เฟรมเวิร์กในการประมวลผลข้อมูลขนาดใหญ่ เช่น Beam หรือ Spark แล้วเรียกใช้ไปป์ไลน์ในระบบคลาวด์
PipelineDP รองรับบีมและ Spark ที่มีการเปลี่ยนแปลงโค้ดเพียงเล็กน้อย
วิธีเรียกใช้ไปป์ไลน์ด้วยบีมด้วย private_beam
API
- เริ่มต้นตัวแปร
runner
แล้วสร้างไปป์ไลน์ที่คุณใช้การดำเนินการด้านความเป็นส่วนตัวกับการแสดงบีมของrows
ดังนี้
runner = fn_api_runner.FnApiRunner() # local runner
with beam.Pipeline(runner=runner) as pipeline:
beam_data = pipeline | beam.Create(rows)
- สร้างตัวแปร
budget_accountant
ที่มีพารามิเตอร์ความเป็นส่วนตัวที่จำเป็น
budget_accountant = pipeline_dp.NaiveBudgetAccountant(
total_epsilon=1, total_delta=0)
- สร้างตัวแปร
pcol
หรือคอลเล็กชันส่วนตัว ซึ่งรับประกันว่าการรวมใดๆ จะเป็นไปตามข้อกำหนดด้านความเป็นส่วนตัวต่อไปนี้
pcol = beam_data | pbeam.MakePrivate(
budget_accountant=budget_accountant,
privacy_id_extractor=lambda
row: row.user_id)
- ระบุพารามิเตอร์ของการรวมข้อมูลส่วนตัวในคลาสที่เหมาะสม
ในที่นี้ คุณใช้คลาส pipeline_dp.aggregate_params.SumParams()
เพราะคำนวณผลรวมของการดูผลิตภัณฑ์
- ส่งพารามิเตอร์การรวมของคุณไปยังเมธอด
pbeam.Sum
เพื่อคำนวณสถิติ:
dp_result = pcol | pbeam.Sum(params)
- ซึ่งในท้ายที่สุด โค้ดของคุณควรมีลักษณะเช่นนี้
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