संपादक की टिप्पणी: यह पोस्ट Milan van der Meer के साथ मिलकर लिखी गई है। इस पोस्ट के दोनों लेखक Real Impact Analytics टीम में हैं, जो एक नवोन्मेषी बेल्जियन बिग डेटा स्टार्टअप है जो "बिग डेटा को ऐपिफाई" करके टेलीकॉम डेटा में मौजूद वैल्यू निकालता है।
यह ट्यूटोरियल बताता है कि आप यादृच्छिक डेटासेट क्यों बनाना चाहेंगे और उनसे क्या अपेक्षा रख सकते हैं। यह आपको Trumania, एक डेटा जनरेशन Python लाइब्रेरी, का उपयोग करने के शुरुआती उदाहरणों से भी गुजारेगा।
अधिक जानकारी के लिए, Trumania का GitHub देखें!
यादृच्छिक डेटासेट क्यों बनाएँ?
यादृच्छिक डेटासेट बनाना डेटा इंजीनियर और डेटा साइंटिस्ट दोनों के लिए उपयोगी है। डेटा साइंटिस्ट और डेटा इंजीनियर सिंथेटिक डेटा के साथ क्यों काम करते हैं, और वे इसे कैसे प्राप्त करते हैं?
एक डेटा इंजीनियर के रूप में, जब आप अपनी नई बेहतरीन डेटा प्रोसेसिंग एप्लिकेशन लिख लेते हैं, तो आपको लगता है कि अब एंड-टू-एंड टेस्टिंग का समय है और इसके लिए आपको कुछ इनपुट डेटा चाहिए।
एक डेटा साइंटिस्ट के रूप में, डेटा जनरेशन से आपको लाभ होता है क्योंकि यह आपको डेटासेट की खोज के विभिन्न तरीकों, एल्गोरिद्म, डेटा विज़ुअलाइज़ेशन तकनीकों के साथ प्रयोग करने या किसी विधि के व्यवहार के बारे में मान्यताओं को आपके चुने हुए कई अलग-अलग डेटासेट पर परखने देता है।
दोनों ही मामलों में, एक लुभावना विकल्प है कि बस वास्तविक डेटा का उपयोग करें। एक छोटी-सी समस्या यह है कि प्रोडक्शन डेटा आमतौर पर आंशिक रूप से भी पाना मुश्किल होता है, और गोपनीयता और सुरक्षा पर नए यूरोपीय कानूनों के साथ यह और कठिन होता जा रहा है।
शायद आप भाग्यशाली हैं—आपके लैपटॉप पर एक अच्छा-सा संपूर्ण प्रोडक्शन डेटा सेट है। फिर भी, आप डेटासेट में अधिक विविधता चाहेंगे ताकि अलग-अलग स्थितियों जैसे अलग-अलग जनसंख्या आकार, अलग-अलग डेटा वितरण, डेटा गुणवत्ता के मुद्दे जैसे मिसिंग या अमान्य डेटा आदि के विरुद्ध वैलिडेट कर सकें...
यह विस्तार से पढ़ने के लिए कि यादृच्छिक डेटासेट बनाना क्यों उपयोगी है, देखें 'Why synthetic data is about to become a major competitive advantage'।
स्कीमा-आधारित यादृच्छिक डेटा जनरेशन: हमें अच्छे रिलेशनशिप चाहिए!
यह अनुभाग स्कीमा-आधारित यादृच्छिक डेटा जनरेशन को दर्शाने और उसकी सीमाएँ दिखाने की कोशिश करता है।
यादृच्छिक डेटासेट बनाने के लिए पहले से कई टूल मौजूद हैं। इन टूल्स में एक आम तरीका स्कीमा-आधारित जनरेशन है, जो आपको एक ब्लूप्रिंट परिभाषित करने और उससे एंटिटीज़ जनरेट करने की सुविधा देता है। Khermes और LogSynth ऐसे ही टूल्स के दो उदाहरण हैं।
स्कीमा-आधारित कॉन्फ़िग का एक उदाहरण शायद इस व्यक्ति-स्कीमा को शामिल करेगा:
{
{
"field": "Name",
"class": NameGenerator
},
{
"field": "Age",
"class": RandomInt(18, 65)
},
{
"field": "Gender",
"class": RandomPicker(["Male", "Female", "Other"])
}
}
यह स्कीमा किसी व्यक्ति के बारे में कुछ डेटा जनरेट करने को परिभाषित करता है। इसमें नाम, उम्र और लिंग शामिल हैं। यह सरल है, तेज़ है, और इसमें कुछ सीमाएँ हैं। एक मुख्य सीमा है अलग-अलग एंटिटीज़ के बीच या समय के आधार पर रिलेशनशिप को यथार्थ रूप में गढ़ पाना।
उदाहरण के लिए, लिंग के आधार पर कुछ नाम अधिक संभावित कैसे बनाएं? या ऐसा यूज़र एक्शन लॉग कैसे बनाएं जिसमें वीकेंड के दौरान एक्शन होने की संभावना अधिक हो?
स्कीमा-आधारित तरीका आपकी नई एप्लिकेशन को वास्तविक दुनिया की खासियतों या कठिनाइयों के सामने लाना आसान नहीं बनाता, जैसे:
- असंतुलित डेटासेट (group-by प्रकार के ऑपरेशनों में कठिनाई);
- एंटिटी नेटवर्क में क्लस्टर्ड पैटर्न; यानी यूज़र इंटरेक्शन (उदाहरण: फोन कॉल) के ज़रिए सामाजिक समूहों की खोज;
- विभिन्न समय-गतिविधि प्रोफाइल; कुछ समय या सप्ताह के कुछ दिनों में एक्शन होने की संभावना अधिक होना;
- एक्शनों के बीच कारणात्मक संबंध; यानी किसी दुकान में बहुत सारी खरीदारी का होना जो अंततः एक "out-of-stock" इवेंट ट्रिगर कर दे।
इन कमियों को दूर करने और अधिक यथार्थवादी डेटासेट बनाने के लिए Trumania परिदृश्य (scenario) पर आधारित है। जैसे-जैसे परिदृश्य आगे बढ़ता है, अलग-अलग आबादियाँ एक-दूसरे के साथ इंटरेक्ट करती हैं, अपनी प्रॉपर्टीज़ अपडेट करती हैं और लॉग उत्पन्न करती हैं।
परिदृश्य का एक उदाहरण होगा—लोग अपने दोस्तों को कॉल कर रहे हों। जब कोई व्यक्ति कॉल करता है तो उसे मिनटों में भुगतान करना पड़ता है; जब मिनट खत्म हो जाते हैं तो उसे दुकान पर जाना होता है... परिणामी डेटासेट यूज़र कॉल का लॉग, शॉपिंग एक्शनों का लॉग और हर घंटे का स्टॉक स्तर हो सकता है। परिदृश्य में एक्शन यादृच्छिक या नियतात्मक (deterministic) दोनों हो सकते हैं।
Trumania में, बनाए गए डेटासेट आम तौर पर टाइम-सीरीज़ होते हैं क्योंकि वे समय के साथ unfold होते परिदृश्य के निष्पादन से उत्पन्न होते हैं।
Trumania के साथ परस्पर-सम्बद्ध डेटा बनाना (यानी ट्यूटोरियल शुरू!)
नीचे दिए गए उदाहरण में, आप देखेंगे कि कैसे आप एक बुनियादी परिदृश्य बनाते हैं जिसमें अलग-अलग लोग एक-दूसरे को संदेश भेजते हैं। परिणामी डेटासेट लोगों के बीच आदान-प्रदान किए गए संदेशों की टाइम-सीरीज़ होगा।
हम जिन चरणों से गुजरेंगे, उनका क्रम इस प्रकार है:
- एक Trumania circus बनाना, जो वह दुनिया है जिसमें परिदृश्य चलेगा
- एक "hello world" कहानी जोड़ना जो बुनियादी हार्ड-कोडेड लॉग बनाएगी
- हर व्यक्ति को कुछ पसंदीदा उद्धरण (quotes) असाइन करने के लिए एक relationship जोड़ना, जिनका उपयोग संदेशों की सामग्री बनाने में होगा
- दिन भर में संदेशों के अधिक यथार्थवादी वितरण के लिए कहानी के समय पैरामीटरों को पैरामीटराइज़ करना
- एक और relationship जोड़ना ताकि एक सोशल नेटवर्क परिभाषित हो सके, जिससे संदेश लॉग से उभरने वाला सोशल ग्राफ अधिक यथार्थवादी हो
Trumania Circus बनाना
उद्देश्य
पहला कदम है एक circus बनाना, जो वह दुनिया है जिसमें परिदृश्य के सभी तत्व मौजूद रहेंगे। हम persons की एक बुनियादी आबादी भी बनाएंगे। चूंकि Trumania के कई पहलू यादृच्छिक हैं, यह कदम generators की अवधारणा भी प्रस्तुत करेगा, जिनका उपयोग कई यादृच्छिक व्यवहारों को नियंत्रित करने में होता है।
हम इस चरण में कोई परिदृश्य नहीं जोड़ेंगे, इसलिए सब कुछ स्थिर रहेगा।
चलिए शुरू करते हैं!
कैसे करें
एक Trumania circus इस तरह बनाया जाता है:
from trumania.core import circus
example_circus = circus.Circus(name="example1",
master_seed=12345,
start=pd.Timestamp("1 Jan 2017 00:00"),
step_duration=pd.Timedelta("1h"))
Trumania में, समय-संबंधी सभी तत्व एक केंद्रीय घड़ी से नियंत्रित होते हैं। ऊपर दिए गए कोड स्निपेट का सबसे महत्वपूर्ण भाग है step_duration=pd.Timedelta("1h"), जो परिभाषित करता है कि घड़ी 1 घंटे के चरणों में बढ़ेगी।
अगले चरण में, आप circus में person आबादी जोड़ते हैं। एक आबादी मूलतः एजेंट्स का एक सेट होती है जिनके पास एक id और कुछ विशेषताएँ होती हैं।
प्रत्येक विशेषता के मानों को मैन्युअली निर्दिष्ट करना संभव है, लेकिन ज्यादातर मामलों में आप उन्हें यादृच्छिक रूप से जनरेट करना चाहेंगे, इसलिए चलिए पहले इसके लिए कुछ generators परिभाषित करते हैं:
from trumania.core.random_generators import SequencialGenerator, FakerGenerator, NumpyRandomGenerator
id_gen = SequencialGenerator(prefix="PERSON_")
age_gen = NumpyRandomGenerator(method="normal", loc=3, scale=5,
seed=next(example_circus.seeder))
name_gen = FakerGenerator(method="name", seed=next(example_circus.seeder))
एक Trumania जनरेटर का काम है कि जब उसका generate() मेथड बुलाया जाए तो वह डेटा प्रदान करे। ऊपर के उदाहरण में, id_gen PERSON_0001, PERSON_0002 जैसी स्ट्रिंग्स जनरेट करेगा... age_gen बार-बार नॉर्मल डिस्ट्रीब्यूशन से सैंपल करेगा और name_gen यादृच्छिक लोगों के नाम देगा।
ध्यान दें कि numpy की कोई भी सांख्यिकीय वितरण और कोई भी Faker प्रोवाइडर Trumania में उपलब्ध है, और Trumania में नए प्रोवाइडर जोड़ना भी आसान है।
अब आप 1000 व्यक्तियों की आबादी, अनुक्रमिक आईडी और दो बुनियादी यादृच्छिक विशेषताओं के साथ जोड़ सकते हैं:
person = example_circus.create_population(name="person", size=1000, ids_gen=id_gen)
person.create_attribute("NAME", init_gen=name_gen)
person.create_attribute("AGE", init_gen=age_gen)
परिणाम
person आबादी के सभी सदस्यों की बनाई गई विशेषताओं को आप person.to_dataframe() बुलाकर देख सकते हैं।
+-------------------+-----------------+---------+
| | NAME | age |
|-------------------+-----------------+---------|
| PERSON_0000000000 | Amy Berger | 28.588 |
| PERSON_0000000001 | Michael Curry | 28.7499 |
| PERSON_0000000002 | Robert Ramirez | 35.9242 |
| PERSON_0000000003 | Derek Gonzalez | 34.7091 |
| PERSON_0000000004 | Gregory Fischer | 25.6009 |
| PERSON_0000000005 | Erica Walker | 33.9758 |
| PERSON_0000000006 | Bradley Collins | 24.4428 |
| PERSON_0000000007 | James Rodriguez | 34.7835 |
| PERSON_0000000008 | Brandy Padilla | 34.6296 |
| PERSON_0000000009 | Mark Taylor | 38.2286 |
+-------------------+-----------------+---------+
टिप: यदि आप इस बुनियादी यूज़र आबादी के लिए पूरा स्क्रिप्ट देखना चाहते हैं, तो यह Github पर स्निपेट देखें!
Hello World स्टेटमेंट्स: स्टोरीज़ बनाना
उद्देश्य
इसे थोड़ा और रोचक बनाते हैं एक story जोड़कर। एक Trumania स्टोरी मूलतः परिदृश्य का वह हिस्सा है जो कुछ गतिशील पहलू को समाहित करता है। हर बार जब सिम्युलेटेड घड़ी एक कदम आगे बढ़ती है, एक स्टोरी निष्पादित होती है।
याद करें कि आपने ऊपर circus में step_duration=pd.Timedelta("1h") सेट किया था, तो इसका मतलब है कि हर लॉजिकल घंटे पर हर स्टोरी को चलने का मौका मिलेगा।
आप एक सरल hello-world स्टोरी बनाएंगे जिसमें ऊपर की person आबादी के सभी सदस्य नियमित रूप से "hello world" संदेश उत्सर्जित करेंगे।
कैसे करें
story बनाते समय पहला मुख्य पहलू है उस आबादी को तय करना जो स्टोरी को इनिशिएट करती है। इस मामले में, यह person होगी। दूसरा पहलू है timer को परिभाषित करना, जो बताता है कि आबादी का प्रत्येक सदस्य वह एक्शन कब ट्रिगर करता है। अभी के लिए, आप उन्हें 1 पर हार्ड-कोड कर रहे हैं, जिसका अर्थ है कि सभी सदस्य हर क्लॉक स्टेप पर स्टोरी चलाएँगे (आप बाद के चरण में और जटिल टाइमर बनाएँगे):
hello_world = example_circus.create_story(
name="hello_world",
initiating_population=example_circus.populations["person"],
member_id_field="PERSON_ID",
timer_gen=ConstantDependentGenerator(value=1)
)
अब तक, स्टोरी खाली है, इसलिए यह कुछ नहीं करती: आपको इसमें कुछ operations जोड़ने होंगे। ऑपरेशंस यादृच्छिक या नियतात्मक हो सकते हैं; वे किसी भी आबादी की विशेषताओं या circus में किसी अन्य स्टेट को पढ़ और अपडेट कर सकते हैं, और साइड-इफेक्ट भी कर सकते हैं।
अभी के लिए, दो सरल नियतात्मक ऑपरेशन और एक लॉगर जोड़ते हैं ताकि हमें लॉग वास्तव में मिलें:
hello_world.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
ConstantGenerator(value="hello world").ops.generate(named_as="MESSAGE"),
FieldLogger(log_id="hello")
)
example_circus.clock.ops.timestamp वर्तमान 1 घंटे के समय-अंतराल के भीतर एक यादृच्छिक timestamp जनरेट करता है और ConstantGenerator स्थिर हार्ड-कोडेड मान पैदा करता है।
परिणाम
चलिए circus को 48 घंटे के सिमुलेटेड समय के लिए चलाते हैं:
example_circus.run(
duration=pd.Timedelta("48h"),
log_output_folder="example_scenario",
delete_existing_logs=True
)
इससे नीचे जैसा बुनियादी डेटासेट बनेगा, जिसमें 1000 में से प्रत्येक व्यक्ति ने 2 दिनों में 48 बार "hello world" कहा।
परिणामी डेटासेट का पहला फ़ील्ड PERSON_ID story के member_id_field से मेल खाता है। बाकी दो फ़ील्ड, TIME और MESSAGE, वे दो मुख्य ऑपरेशन हैं जो आपने अपनी स्टोरी में डाले।
+-------+-------------------+---------------------+-------------+
| | PERSON_ID | TIME | MESSAGE |
|-------+-------------------+---------------------+-------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | hello world |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | hello world |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | hello world |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | hello world |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | hello world |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | hello world |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | hello world |
| 7 | PERSON_0000000007 | 2017-01-01 01:24:30 | hello world |
| 8 | PERSON_0000000008 | 2017-01-01 01:01:51 | hello world |
| 9 | PERSON_0000000009 | 2017-01-01 01:41:41 | hello world |
| ... |
| 23990 | PERSON_0000000990 | 2017-01-02 23:33:28 | hello world |
| 23991 | PERSON_0000000991 | 2017-01-02 23:15:26 | hello world |
| 23992 | PERSON_0000000992 | 2017-01-02 23:45:56 | hello world |
| 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | hello world |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | hello world |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | hello world |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | hello world |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | hello world |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | hello world |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | hello world |
+-------+-------------------+---------------------+-------------+
टिप: पूरा स्निपेट Github पर देखें
Hello World कहने के लिए कोई तो हो
उद्देश्य
इसे थोड़ा और सुधारते हैं बातचीत में एक और यादृच्छिक व्यक्ति जोड़कर। अभी के लिए, मान लेते हैं कि कोई भी व्यक्ति समान संभावना के साथ किसी भी अन्य व्यक्ति से बात कर सकता है, जो बहुत यथार्थवादी नहीं है (आप बाद के चरण में एक सोशल नेटवर्क जोड़ेंगे)। साथ ही, आप लोगों के आईडी के आधार पर उनके नाम जोड़कर डेटासेट को समृद्ध करेंगे।
कैसे करें
मान लें कि दूसरे व्यक्ति को एक नए OTHER_PERSON फ़ील्ड में रखा जाएगा। इस सरल मामले में, आप बस person आबादी में से एक यादृच्छिक, बिना वेटिंग वाला चयन इस फ़ील्ड में रखना चाहते हैं। आप सीधे उस आबादी के select_one यादृच्छिक ऑपरेशन का उपयोग कर सकते हैं:
example_circus.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
ConstantGenerator(value="hello world").ops.generate(named_as="MESSAGE"),
example_circus.populations["person"].ops.select_one(named_as="OTHER_PERSON"),
example_circus.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
example_circus.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={"NAME": "RECEIVER_NAME"}),
FieldLogger(log_id="hello")
)
परिणाम
जब आप circus को फिर चलाते हैं, तो आपको नए OTHER_PERSON फ़ील्ड वाला डेटासेट मिलेगा:
+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | hello world | PERSON_0000000852 | Ann Cruz | Sophia Black |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | hello world | PERSON_0000000429 | Kimberly Sanchez | Jeffrey Ryan |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | hello world | PERSON_0000000925 | Bethany Smith | Regina Brown |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | hello world | PERSON_0000000347 | Frank Middleton | Jacob Ross |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | hello world | PERSON_0000000211 | Cheryl Decker | Joshua Miller |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | hello world | PERSON_0000000779 | Thomas Rodriguez | Nicole Tanner |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | hello world | PERSON_0000000331 | James Peters | Melissa Rogers |
| 7 | PERSON_0000000007 | 2017-01-01 01:24:30 | hello world | PERSON_0000000234 | Allison Hansen | Taylor Smith |
| 8 | PERSON_0000000008 | 2017-01-01 01:01:51 | hello world | PERSON_0000000678 | Candice Sellers | James Smith |
| 9 | PERSON_0000000009 | 2017-01-01 01:41:41 | hello world | PERSON_0000000108 | Maria White | James Nguyen |
| ... |
| 23990 | PERSON_0000000990 | 2017-01-02 23:33:28 | hello world | PERSON_0000000689 | Natasha Brown | Bailey Ramirez DDS |
| 23991 | PERSON_0000000991 | 2017-01-02 23:15:26 | hello world | PERSON_0000000250 | Shelly Ponce | Jordan Johnson |
| 23992 | PERSON_0000000992 | 2017-01-02 23:45:56 | hello world | PERSON_0000000413 | Steven Mendez | Crystal Duffy |
| 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | hello world | PERSON_0000000670 | Morgan Rice | Jonathan Obrien |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | hello world | PERSON_0000000411 | Crystal Vincent | George Mathis |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | hello world | PERSON_0000000563 | Dawn Kim | Jennifer Martinez |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | hello world | PERSON_0000000668 | Jimmy Franco | Dr. Mark Ruiz MD |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | hello world | PERSON_0000000268 | Christian Christian | Victoria Donovan |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | hello world | PERSON_0000000829 | David Hernandez | Margaret Anderson |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | hello world | PERSON_0000000944 | Tamara Ramirez | Andrew Curtis |
+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+
टिप: पूरा कोड आप यहाँ देख सकते हैं
आप हमेशा यही कहते हैं
उद्देश्य
इसे और बेहतर बनाते हैं MESSAGE फ़ील्ड में उबाऊ hello world की जगह एक यादृच्छिक वाक्य जनरेट करके। इससे आप Trumania के Relationship के एक बुनियादी उपयोग को दिखा सकेंगे।
आप प्रत्येक व्यक्ति को 4 उद्धरण असाइन करने जा रहे हैं। जब भी कोई व्यक्ति संदेश भेजेगा, तो सामग्री उसके 4 उद्धरणों में से चुनी जाएगी। इसके अलावा, आप प्रत्येक उद्धरण को अलग-अलग weight देंगे जो यह परिभाषित करेगा कि वह उद्धरण कितना संभावित है: उच्च weight वाला उद्धरण अपने मालिक द्वारा कम weight वाले उद्धरण की तुलना में अधिक बार उपयोग किया जाएगा।
अब शुरुआत कैसे करें?
कैसे करें
पहला कदम है एक quote जनरेटर बनाना, जो ऊपर देखे गए अन्य Faker जनरेटर्स जैसा ही है:
quote_generator = FakerGenerator(method="sentence", nb_words=6, variable_nb_words=True,
seed=next(example_circus.seeder))
आप इस जनरेटर का वैसे ही story में उपयोग कर सकते हैं, लेकिन चलिए चीज़ों को थोड़ा रोचक बनाते हैं—हर व्यक्ति को हमेशा उसके 4 पसंदीदा उद्धरणों में से ही उपयोग करने के लिए बाध्य करके। आप यह person आबादी के सदस्यों और कुछ वाक्य मानों के बीच एक Relationship बनाकर करते हैं।
पहले, एक खाली relationship बनाते हैं:
quotes_rel = example_circus.populations["person"].create_relationship("quotes")
फिर, आप इस relationship को प्रत्येक व्यक्ति के लिए 4 उद्धरणों से भरते हैं। नीचे के कोड में person.ids person आबादी के सभी आईडी के साथ आकार 1000 की एक pandas Series है, और quote_generator.generate(size=person.size) भी आकार 1000 की एक और pandas Series देता है, जिसमें यादृच्छिक उद्धरण होते हैं।
इसका अर्थ है कि नीचे का हर for-लूप पास relationship में 1000 रिलेशन जोड़ता है: 1000 यूज़र्स में से प्रत्येक में एक उद्धरण जोड़ना। पहले 1000 उद्धरणों को weight=1 दिया जाएगा, अगले को weight=2 देकर उन्हें अधिक बार आने योग्य बनाया जाएगा, ...
for w in range(4):
quotes_rel.add_relations(
from_ids=person.ids,
to_ids=quote_generator.generate(size=person.size),
weights=w
)
अब आप अपनी स्टोरी में ConstantGenerator की जगह उस relationship पर select_one ऑपरेशन लगा सकते हैं। इसका अर्थ इस प्रकार पढ़ा जा सकता है: PERSON_ID फ़ील्ड में जो भी मान वर्तमान में है, उसके लिए quotes में उस आईडी से शुरू होने वाले रिलेशन ढूंढें और संबंधित मानों में से एक को यादृच्छिक रूप से चुनें। चूंकि नीचे के ऑपरेशन में कोई weight ओवरराइड नहीं किए गए हैं, इसलिए ऊपर add_relations में परिभाषित डिफ़ॉल्ट relationship weights का उपयोग होगा:
example_circus.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
example_circus.populations["person"].get_relationship("quotes")
.ops.select_one(from_field="PERSON_ID", named_as="MESSAGE"),
example_circus.populations["person"].ops.select_one(named_as="OTHER_PERSON"),
example_circus.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
example_circus.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={"NAME": "RECEIVER_NAME"}),
FieldLogger(log_id="hello")
)
परिणाम
जब आप circus चलाते हैं, तो MESSAGE फ़ील्ड में अब यादृच्छिक उद्धरण होना चाहिए:
+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | Become period risk wait now toward less. | PERSON_0000000158 | Ann Cruz | Victoria Washington |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | Month push down. | PERSON_0000000366 | Kimberly Sanchez | Steven Williams |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | Blue general carry else deep problem area. | PERSON_0000000613 | Bethany Smith | Frances Davis |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | Phone sister pretty suddenly allow conference. | PERSON_0000000086 | Frank Middleton | Ashley Fernandez |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | Each discussion several send wide process. | PERSON_0000000972 | Cheryl Decker | Latoya Flynn |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | Guess can issue writer. | PERSON_0000000030 | Thomas Rodriguez | Lindsay Bailey |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | Boy step claim camera common but our. | PERSON_0000000548 | James Peters | Thomas Ward |
| ... | 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | May course and kill from news. | PERSON_0000000202 | Morgan Rice | Patricia Williams |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | Water door live hospital together safe. | PERSON_0000000268 | Crystal Vincent | Victoria Donovan |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | Stage control management read although thousand. | PERSON_0000000466 | Dawn Kim | Ashley Baxter |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | Their that region majority break article. | PERSON_0000000620 | Jimmy Franco | Alex Dominguez |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | Lead simple audience response eye. | PERSON_0000000319 | Christian Christian | David Smith |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | Vote man son yeah child. | PERSON_0000000487 | David Hernandez | Joshua Park |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | Answer region wind condition someone bed cover. | PERSON_0000000237 | Tamara Ramirez | Beverly Rodriguez |
+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+
उद्धरणों के लिए उपयोग किए गए relationship का सार यह है कि अब बनाए गए डेटासेट के फ़ील्ड परस्पर सम्बद्ध हैं: कुछ वाक्य कुछ उपयोगकर्ताओं द्वारा अधिक बार उपयोग किए जाते हैं।
टिप: पूरा कोड स्निपेट Github पर देखें
मुद्दा क्या करते हैं नहीं, कब करते हैं यह है
उद्देश्य
अब तक, person आबादी का प्रत्येक सदस्य दिन के हर घंटे ठीक एक संदेश बना रहा है। इसे थोड़ा अधिक यथार्थवादी बनाते हैं।
Trumania स्टोरी के समय पहलू को नियंत्रित करने के लिए 2 अवधारणाओं के संयोजन का उपयोग करता है: activity levels और timer profiles। साथ मिलकर, ये किसी विशिष्ट यूज़र और दिन के समय को देखते हुए story के ट्रिगर होने की संभावना निर्धारित करते हैं।
कैसे करें
आप story को अपडेट करेंगे और इन दोनों पहलुओं को पैरामीटराइज़ करेंगे।
पहले, स्टोरी का timer profile बनाते हैं, जो नियंत्रित करता है कि कब ज़्यादा या कम एक्शन ट्रिगर होंगे। यह प्रोफाइल उस आबादी के सभी सदस्यों के लिए समान है जो स्टोरी को ट्रिगर करते हैं।
Trumania में कुछ रोचक डिफ़ॉल्ट प्रोफाइल बिल्ट-इन आते हैं, जैसे DefaultDailyTimerGenerator, जो एक वास्तविक प्रोडक्शन डेटासेट पर मापे गए दैनिक फोन उपयोग से मेल खाता है:

अपने परिदृश्य में एक को इंस्टेंशिएट करते हैं:
from trumania.components.time_patterns.profilers import DefaultDailyTimerGenerator
story_timer_gen = DefaultDailyTimerGenerator(
clock=example_circus.clock,
seed=next(example_circus.seeder))
दूसरा, स्टोरी के लिए आबादी के सदस्य की activity लेवल है, जो बताती है कि हर यूज़र उस स्टोरी के भीतर कितना सक्रिय है। आपके पास प्रत्येक सदस्य के लिए अलग स्तर सेट करने की स्वतंत्रता है, ताकि कुछ सदस्य अन्य की तुलना में वह एक्शन अधिक या कम बार ट्रिगर करें।
यदि आप चाहें तो आप हर स्तर मैन्युअली निर्दिष्ट कर सकते हैं, हालांकि यहाँ आप बस एक यादृच्छिक जनरेटर का उपयोग करेंगे जो हर आबादी सदस्य को एक activity level असाइन करेगा।
पहले, हम 3, 10 और 20 ट्रिगर्स प्रति दिन औसतन वाले तीन activity levels परिभाषित करते हैं:
low_activity = story_timer_gen.activity(n=3, per=pd.Timedelta("1 day"))
med_activity = story_timer_gen.activity(n=10, per=pd.Timedelta("1 day"))
high_activity = story_timer_gen.activity(n=20, per=pd.Timedelta("1 day"))
फिर, आप वास्तविक activity जनरेटर बना सकते हैं, जो इस बार choice मेथड पर आधारित एक और Numpy जनरेटर होगा। नीचे दिया गया जनरेटर आबादी के 20% को low activity, 70% को medium activity और 10% को high activity असाइन करेगा:
activity_gen = NumpyRandomGenerator(
method="choice",
a=[low_activity, med_activity, high_activity],
p=[.2, .7, .1],
seed=next(example_circus.seeder))
और अब आप इस टाइमर प्रोफाइल और activity जनरेटर को अपनी स्टोरी का हिस्सा बना सकते हैं:
hello_world = example_circus.create_story(
name="hello_world",
initiating_population=example_circus.populations["person"],
member_id_field="PERSON_ID",
timer_gen=story_timer_gen,
activity_gen=activity_gen
)
परिणाम
परिणामी डेटासेट का स्कीमा पहले जैसा ही है:
+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------|
| 0 | PERSON_0000000016 | 2017-01-01 00:14:12 | Still try sex sure. | PERSON_0000000739 | Johnny Moore | Adam Barrett |
| 1 | PERSON_0000000063 | 2017-01-01 00:23:51 | Resource magazine wide. | PERSON_0000000511 | Cody Pham | Tina Simmons |
| 2 | PERSON_0000000064 | 2017-01-01 00:37:11 | Heat sure simple letter better forget. | PERSON_0000000044 | Katherine Fleming | Angela Gray |
| 3 | PERSON_0000000076 | 2017-01-01 00:33:12 | Star our conference always place ball. | PERSON_0000000959 | Benjamin Reese II | Barbara Alexander |
| 4 | PERSON_0000000088 | 2017-01-01 00:08:02 | Hot event five left become time commercial. | PERSON_0000000000 | Zachary Cook | Ann Cruz |
| ... |
| 28556 | PERSON_0000000962 | 2017-01-04 00:07:45 | Then include rock rule scientist condition. | PERSON_0000000448 | Johnny Washington | Melissa Adams |
| 28557 | PERSON_0000000980 | 2017-01-04 00:04:44 | Collection full argue interview property pattern never. | PERSON_0000000731 | James Ramirez | David Morrow |
| 28558 | PERSON_0000000983 | 2017-01-04 00:23:21 | High day prepare see. | PERSON_0000000509 | Evan Horne | Robert Sims |
| 28559 | PERSON_0000000988 | 2017-01-04 00:43:56 | Likely south school result case federal seat. | PERSON_0000000819 | Benjamin Campbell | Michelle Jackson DDS |
+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+
टिप: Github पर स्निपेट देखें
परिणाम एनालिटिक्स
आपने अपने परिदृश्य की कॉन्फ़िगरेशन में जो टाइम पैटर्न शामिल किए हैं, वे अब परिणामी डेटासेट की भीतरी संरचना में दिखने चाहिए। आप इसे resulting_dataset पर एक बुनियादी डेटा विश्लेषण करके दिखा सकते हैं:
- दिन के प्रत्येक घंटे पर संदेशों की संख्या निर्दिष्ट वितरण का अनुसरण करनी चाहिए (ध्यान दें कि यह ऊपर दिए गए
DefaultDailyTimerGeneratorके कर्व से कितना मिलता-जुलता है):
time_profile = (
resulting_dataset[["MESSAGE", "TIME"]]
.groupby(by=example_5_df.TIME.dt.hour)["MESSAGE"]
.count()
)
time_profile.plot()

- प्रति यूज़र संदेशों की संख्या का हिस्टोग्राम भी आपकी कॉन्फ़िगरेशन का सम्मान करना चाहिए:
- आपने
low_activityको औसतन प्रतिदिन 3 संदेश,med_activityको 10 औरhigh_activityको 20 पर कॉन्फ़िगर किया है और सिमुलेशन 5 दिनों तक चलाया है। इससे लगभग 15, 50 और 100 कुल संदेशों वालेpersonके 3 समूह मिलने चाहिए, जो नीचे हिस्टोग्राम के 3 केंद्रों से मेल खाते हैं - आपने इन activity levels की संभावनाएँ .2, .7 और .1 सेट की थीं, और यह फिर हिस्टोग्राम के प्रत्येक “बंप” के क्षेत्रफल से लगभग मेल खाती हैं:
- आपने
usage_per_user = resulting_dataset[["MESSAGE", "PERSON_ID"]].groupby("PERSON_ID")["MESSAGE"].count()
usage_per_user.plot(kind="hist")

The Social Network
उद्देश्य
आप परिदृश्य को और बेहतर बना सकते हैं लोगों को इस तरह जोड़कर कि वे आपकी स्टोरी के निष्पादन के दौरान अपने दोस्तों को संदेश भेजें, न कि किसी यादृच्छिक व्यक्ति को। इससे परिणामी डेटासेट में काफी संरचना आ जाएगी क्योंकि अब संदेश लॉग से सोशल ग्राफ खोजा जा सकेगा।
कैसे करें
आप सोशल नेटवर्क को फिर से एक Relationship से मॉडल कर सकते हैं, जो वही अवधारणा है जिसे आपने ऊपर उद्धरणों के लिए इस्तेमाल किया था। आपको याद होगा कि quotes relationship में एक weight था। वह weight किसी व्यक्ति के संदर्भ में किस उद्धरण के अधिक या कम संभावित होने को परिभाषित करता था। आप यहाँ भी वही कर सकते हैं और weights का उपयोग करके यह परिभाषित कर सकते हैं कि किन दोस्तों को अन्य की तुलना में अधिक या कम संभावना से कॉल किया जाएगा।
ध्यान दें कि यहाँ आप person से person के बीच relationship परिभाषित कर रहे हैं, हालांकि सामान्यतः Trumania आपको किसी भी दो आबादियों के बीच relationships परिभाषित करने देता है।
सोशल ग्राफ की edges जनरेट करने के कई तरीके हैं। एक बुनियादी और पारंपरिक तरीका है Erdos-Renyi एल्गोरिद्म पर निर्भर करना। Trumania में यह खास तौर पर आसान है क्योंकि यह पहले से फ्रेमवर्क में मौजूद है। आपको बस इसे अपने परिदृश्य में इंजेक्ट करके एक relationship बनाना है।
यहाँ, आप person relationship के सदस्यों के बीच एक सोशल ग्राफ परिभाषित करेंगे जिसमें प्रत्येक व्यक्ति के 20 दोस्त होंगे। ध्यान दें कि इस relationship में स्वतः ही Pareto वितरण के साथ एक weight जोड़ दिया जाएगा।
from trumania.components.social_networks.erdos_renyi import WithErdosRenyi
# self यहाँ circus है, विवरण के लिए github पर उदाहरण कोड देखें
self.add_er_social_network_relationship(
self.populations["person"],
relationship_name="friends",
average_degree=20)
इस relationship के साथ, आप अपनी स्टोरी को फिर से देख सकते हैं। इस बार, OTHER_PERSON आबादी में से यादृच्छिक रूप से नहीं चुना जाएगा, बल्कि प्रत्येक person सदस्य के दोस्तों में से चुना जाएगा, उस संभावना के अनुपात में जो सोशल नेटवर्क में परिभाषित weight से तय होती है:
hello_world.set_operations(
self.clock.ops.timestamp(named_as="TIME"),
self.populations["person"].get_relationship("quotes")
.ops.select_one(from_field="PERSON_ID",named_as="MESSAGE"),
self.populations["person"]
.get_relationship("friends")
.ops.select_one(from_field="PERSON_ID", named_as="OTHER_PERSON"),
self.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
self.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={
"NAME": "RECEIVER_NAME"}),
operations.FieldLogger(log_id="hello_6")
)
परिणाम
एक बार फिर, परिणामी डेटासेट का डेटा स्कीमा पहले जैसा ही है, हालांकि इस बार आपके बुनियादी सोशल नेटवर्क की बदौलत इसमें पहले से भी अधिक संरचना है:
+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------|
| 0 | PERSON_0000000004 | 2017-01-01 00:14:12 | Clearly see sure. | PERSON_0000000321 | Cheryl Decker | Ian White |
| 1 | PERSON_0000000012 | 2017-01-01 00:23:51 | Offer or interview clear structure watch capital. | PERSON_0000000697 | Kelly Green | Ashley Turner |
| 2 | PERSON_0000000018 | 2017-01-01 00:37:11 | Recently race draw thousand around ahead. | PERSON_0000000989 | Laura Stephenson | Hannah James |
| 3 | PERSON_0000000040 | 2017-01-01 00:33:12 | To protect man image power beyond. | PERSON_0000000418 | Jeffrey Miller | Scott Collins |
... |
| 28966 | PERSON_0000000985 | 2017-01-04 00:09:23 | However agreement fear door land hotel. | PERSON_0000000211 | Laura Mason | Joshua Miller |
| 28967 | PERSON_0000000995 | 2017-01-04 00:48:08 | Top heat window quite forward friend somebody. | PERSON_0000000171 | Dawn Kim | Sandra Phillips |
| 28968 | PERSON_0000000999 | 2017-01-04 00:58:46 | Answer region wind condition someone bed cover. | PERSON_0000000252 | Tamara Ramirez | Jordan Collins |
+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+
टिप: Github पर स्निपेट देख सकते हैं
परिणाम एनालिटिक्स
उस सोशल नेटवर्क को देखने का एक बहुत ही मोटा तरीका है कि हर व्यक्ति द्वारा कॉल किए गए अद्वितीय दोस्तों की संख्या गिन ली जाए। यदि आप सिमुलेशन को पर्याप्त समय तक चलाते हैं, तो इससे प्रत्येक व्यक्ति के सोशल नेटवर्क में वास्तविक लोगों की संख्या की एक निम्न सीमा मिलेगी (क्योंकि आप Pareto वितरण वाले weights का उपयोग कर रहे हैं, कई लोगों के ऐसे दोस्त होंगे जिनको कॉल किए जाने की संभावना वाकई बहुत कम है, इसलिए प्रत्येक संभव कॉल्ड व्यक्ति को देखने के लिए सिमुलेशन को बहुत लंबा चलाने की आवश्यकता है)।
आपने हमारा परिदृश्य 15 सिम्युलेटेड दिनों के लिए चलाया और यह प्राप्त किया, जो आपके सोशल ग्राफ में सेट किए गए औसत डिग्री 20 के क़रीब और उससे थोड़ा कम केंद्रित है:
social_group_size = (
resulting_dataset[["PERSON_ID", "OTHER_PERSON"]]
.groupby("PERSON_ID")
.agg(lambda friends_ids: len(friends_ids.unique()))
)
social_group_size.plot(kind="hist")

और भी बहुत कुछ है!
इस पोस्ट में Trumania की कई विशेषताओं का वर्णन नहीं किया गया है:
- किसी परिदृश्य में कई आबादियाँ होना
- किसी परिदृश्य में कई स्टोरीज़ होना
- स्टोरीज़ के बीच प्रायिकताएं आधारित निर्भरताएँ जोड़ना (उदा. किसी व्यक्ति का कॉल आना और उसके बाद वह दोस्त को कॉल करना)
- स्टेट अपडेट (उदा. फोन कॉल की अवधि के आधार पर बैलेंस अकाउंट को घटाना)
- परिदृश्य के पुन: प्रयोज्य हिस्से, जैसे भौगोलिक क्षेत्र, अधिक टाइमर प्रोफाइल, ...
- परिदृश्य के हिस्सों का परसिस्टेंस
निष्कर्ष
हमने Trumania का परिचय एक परिदृश्य-आधारित डेटा जनरेटर लाइब्रेरी के रूप में कराया है, जो Python में है। बनाए गए डेटासेट का उपयोग टेस्टिंग, सीखने और बेंचमार्किंग जैसी कई एप्लिकेशनों में किया जा सकता है।
हमने समझाया कि किसी एप्लिकेशन या एल्गोरिद्म का ठीक से परीक्षण करने के लिए हमें ऐसे डेटासेट चाहिए जो अपेक्षित सांख्यिकीय गुणों का सम्मान करें। हमने दिखाया कि Trumania ऐसा करने में सक्षम है—एक उदाहरण में जहाँ हमने एक बुनियादी "message log" डेटासेट बनाया जो प्रति यूज़र संदेशों की संख्या के वितरण, दिन के समय के वितरण और सोशल ग्राफ के बीच कॉल के वितरण का सम्मान करता है।
हमें उम्मीद है कि हमने यह भी दिखाया कि Trumania के घटकों की लचीलापन कई प्रकार के परिदृश्यों के निर्माण की अनुमति देता है।
एक Trumania परिदृश्य में एंटिटीज़ के बीच रिश्ते शामिल हो सकते हैं और इसे सैद्धांतिक यादृच्छिक वितरणों, किसी वास्तविक डेटासेट में देखे गए प्रायोगिक वितरणों या यहाँ तक कि वास्तविक प्रोडक्शन डेटा (उदा. लोकेशन आईडी का डेटासेट) से कॉन्फ़िगर किया जा सकता है। हमने इसे इस तरह प्रदर्शित किया कि एक वास्तविक डेटासेट में देखे गए फोन उपयोग के timestamp के सांख्यिकीय वितरण का पुन: उपयोग करके अपनी स्टोरी के समय के यादृच्छिक टाइमर को कॉन्फ़िगर किया।
अब यह सब ध्यान में रखते हुए, जमकर प्रयोग करें! Trumania के Github पर जाएँ और अपना खुद का परिदृश्य लिखें ;)
अन्यथा, निःसंकोच Svend Vanderveken या सह-लेखक Milan van der Meer से संपर्क करें:
- Svend Vanderveken एक फ्रीलांस सॉफ्टवेयर इंजीनियर हैं, जिन्हें डेटा-प्रोसेसिंग सॉल्यूशंस, खासकर Kafka, Scala, SQL, Python आदि में विशेषज्ञता है। उनके ब्लॉग svend.kelesia.com और ट्विटर @sv3ndk पर उन्हें फ़ॉलो करें।
- Milan van der Meer वर्तमान में Real Impact Analytics में सॉफ्टवेयर इंजीनियर के रूप में काम करते हैं। आप उनसे हमेशा LinkedIn पर कनेक्ट हो सकते हैं।
संपादक की टिप्पणी: यह पोस्ट Milan van der Meer के साथ सहयोग में लिखी गई है। इस पोस्ट के दोनों लेखक Real Impact Analytics टीम में हैं, जो एक नवोन्मेषी बेल्जियन बिग डेटा स्टार्टअप है जो "बिग डेटा को ऐपिफाई" करके दूरसंचार डेटा का मूल्य निकालता है।
यह ट्यूटोरियल इस बात की एक छोटी-सी झलक देता है कि आप रैंडम डेटासेट क्यों बनाना चाहेंगे और उनसे क्या अपेक्षा करें। यह आपको Trumania, एक डेटा जेनरेशन Python लाइब्रेरी, का उपयोग करने के शुरुआती उदाहरणों से भी गुजारेगा।
अधिक जानकारी के लिए आप Trumania के GitHub पर जा सकते हैं!
रैंडम डेटासेट क्यों बनाएँ?
रैंडम डेटासेट बनाना डेटा इंजीनियर्स और डेटा साइंटिस्ट्स—दोनों—के लिए उपयोगी है। डेटा साइंटिस्ट्स और डेटा इंजीनियर्स सिंथेटिक डेटा के साथ क्यों काम करते हैं और वे उसे कैसे प्राप्त करते हैं?
एक डेटा इंजीनियर के रूप में, जब आपने अपना नया बेहतरीन डेटा प्रोसेसिंग एप्लिकेशन लिख लिया है, तो आपको लगता है कि अब एंड-टु-एंड परीक्षण शुरू करने का समय है, और इसके लिए आपको कुछ इनपुट डेटा चाहिए।
एक डेटा साइंटिस्ट के रूप में, डेटा जेनरेशन से आपको फायदा होता है क्योंकि यह आपको डाटासेट्स, एल्गोरिद्म, डेटा विज़ुअलाइज़ेशन तकनीकों की खोज के विभिन्न तरीकों के साथ प्रयोग करने या किसी विधि के व्यवहार के बारे में मान्यताओं को आपके चुने हुए कई अलग-अलग डाटासेट्स के विरुद्ध सत्यापित करने की अनुमति देता है।
दोनों ही मामलों में, एक आकर्षक विकल्प है वास्तविक डेटा का उपयोग करना। लेकिन एक छोटी सी समस्या यह है कि प्रोडक्शन डेटा आमतौर पर प्राप्त करना कठिन होता है, यहां तक कि आंशिक रूप से भी, और नई यूरोपीय गोपनीयता और सुरक्षा से संबंधित क़ानूनों के साथ यह और आसान नहीं हो रहा है।
हो सकता है आप भाग्यशाली हों और आपके लैपटॉप पर एक बढ़िया, पूर्ण प्रोडक्शन डेटासेट हो। तब भी, आप विभिन्न परिस्थितियों—जैसे अलग-अलग जनसंख्या आकार, अलग-अलग डेटा वितरण, विभिन्न डेटा गुणवत्ता समस्याएँ जैसे मिसिंग या अमान्य डेटा—के विरुद्ध सत्यापन के लिए डेटासेट में अधिक परिवर्तनशीलता चाहेंगे...
इस पर अधिक विस्तार से पढ़ने के लिए कि रैंडम डेटासेट बनाना क्यों उपयोगी है, यहाँ जाएँ: 'Why synthetic data is about to become a major competitive advantage'।
स्कीमा-आधारित रैंडम डेटा जेनरेशन: हमें अच्छे संबंध चाहिए!
यह भाग स्कीमा-आधारित रैंडम डेटा जेनरेशन को दर्शाने और उसकी सीमाएँ दिखाने की कोशिश करता है।
रैंडम डाटासेट्स बनाने के लिए पहले से ही अनेक टूल मौजूद हैं। उन टूल्स में एक आम तरीका स्कीमा-आधारित जेनरेशन है जो आपको एक ब्लूप्रिंट परिभाषित करने और उससे एंटिटीज़ बनाने की अनुमति देता है। Khermes और LogSynth ऐसे टूल्स के दो उदाहरण हैं।
स्कीमा-आधारित कॉन्फ़िग का एक उदाहरण शायद इस व्यक्ति-स्कीमा को शामिल करेगा:
{
{
"field": "Name",
"class": NameGenerator
},
{
"field": "Age",
"class": RandomInt(18, 65)
},
{
"field": "Gender",
"class": RandomPicker(["Male", "Female", "Other"])
}
}
यह स्कीमा किसी व्यक्ति के बारे में कुछ डेटा के निर्माण को परिभाषित करता है। इसमें नाम, आयु और लिंग है। यह सरल है, जल्दी है, और कुछ सीमाएँ भी हैं। एक मुख्य सीमा है विभिन्न एंटिटीज़ के बीच या समय-आधारित संबंधों को वास्तविक रूप से दर्शाना।
उदाहरण के लिए, लिंग के आधार पर कुछ नामों को अधिक संभाव्य कैसे बनाया जाए? या यूज़र एक्शन्स का ऐसा लॉग कैसे बनाया जाए जिसमें वीकेंड के दौरान एक्शन होने की संभावना अधिक हो?
स्कीमा-आधारित तरीका आपकी नई एप्लिकेशन को वास्तविक दुनिया की विशिष्टताओं या कठिनाइयों के संपर्क में लाना आसान नहीं बनाता, जैसे:
- असंतुलित डाटासेट्स (group-by जैसी ऑपरेशनों में कठिनाई);
- एंटिटी नेटवर्क में क्लस्टर्ड पैटर्न। यानी, यूज़र इंटरैक्शन्स (उदाहरण के लिए, फोन कॉल्स) के माध्यम से सामाजिक समूहों की खोज करना;
- विभिन्न समय-गतिविधि प्रोफ़ाइल। कुछ क्रियाएँ दिन या सप्ताह के कुछ समय पर अधिक संभाव्य होती हैं;
- क्रियाओं के बीच कारणात्मक संबंध। जैसे, किसी दुकान पर कई खरीद क्रियाएँ जो अंततः "आउट-ऑफ-स्टॉक" इवेंट को ट्रिगर करती हैं।
Trumania इन कमियों को दूर करने और अधिक यथार्थपरक डाटासेट्स बनाने के लिए परिदृश्य (scenario) पर आधारित है। जैसे-जैसे परिदृश्य आगे बढ़ता है, विभिन्न आबादियाँ एक-दूसरे के साथ इंटरैक्ट करती हैं, अपनी विशेषताएँ अपडेट करती हैं और लॉग उत्पन्न करती हैं।
एक परिदृश्य का उदाहरण होगा लोगों का अपने दोस्तों को कॉल करना। जब कोई व्यक्ति कॉल करता है तो उसे मिनटों में भुगतान करना पड़ता है, जब मिनट खत्म हो जाते हैं तो उसे दुकान पर जाना पड़ता है... परिणामी डाटासेट यूज़र कॉल्स का लॉग, शॉपिंग क्रियाओं का लॉग और हर घंटे का स्टॉक स्तर हो सकता है। परिदृश्य में क्रियाएँ रैंडम भी हो सकती हैं और निर्धारक (deterministic) भी।
Trumania में, बनाए गए डाटासेट्स आमतौर पर टाइम-सीरीज़ होते हैं क्योंकि वे किसी ऐसे परिदृश्य के निष्पादन का परिणाम होते हैं जो समय के साथ आगे बढ़ता है।
Trumania के साथ आपस में संबंधित डेटा बनाना (यानी ट्यूटोरियल का समय!)
नीचे के उदाहरण में, आप देखेंगे कि आप एक बुनियादी परिदृश्य कैसे तैयार कर सकते हैं जिसमें विभिन्न लोग एक-दूसरे को संदेश भेजते हैं। परिणामी डाटासेट लोगों के बीच आदान-प्रदान किए गए संदेशों की टाइम सीरीज़ होगा।
हम जिन चरणों से गुजरेंगे, उनका क्रम इस प्रकार है:
- Trumania का एक circus बनाना, जो वह दुनिया है जिसमें परिदृश्य निष्पादित होगा
- एक "hello world" स्टोरी जोड़ना जो बुनियादी हार्ड-कोडेड लॉग्स उत्पन्न करेगी
- एक relationship जोड़ना ताकि हर व्यक्ति को कुछ पसंदीदा उद्धरण सौंपे जा सकें, जिनका उपयोग संदेशों की विषयवस्तु बनाने के लिए किया जाएगा।
- दिन भर में संदेशों के अधिक यथार्थपरक वितरण के लिए स्टोरी के समय-संबंधी पैरामीटर्स को सेट करना
- एक और रिलेशनशिप जोड़ना ताकि एक सामाजिक नेटवर्क परिभाषित हो सके, जिससे संदेश लॉग से उभरने वाला सोशल ग्राफ अधिक यथार्थपरक हो
Trumania सर्कस बनाना
उद्देश्य
पहला कदम एक circus बनाना है, जो वह दुनिया है जिसमें परिदृश्य के सभी तत्व मौजूद होंगे। हम एक बुनियादी persons आबादी भी बनाएँगे। चूँकि Trumania के कई पहलू रैंडम होते हैं, यह कदम generators की अवधारणा भी पेश करेगा, जिनका उपयोग कई रैंडम व्यवहारों को नियंत्रित करने के लिए किया जाता है।
हम इस समय कोई परिदृश्य नहीं जोड़ेंगे, इसलिए सब कुछ स्थिर रहेगा।
चलिए शुरू करते हैं!
कैसे करें
Trumania सर्कस इस तरह सरलता से बनाया जाता है:
from trumania.core import circus
example_circus = circus.Circus(name="example1",
master_seed=12345,
start=pd.Timestamp("1 Jan 2017 00:00"),
step_duration=pd.Timedelta("1h"))
Trumania में, सभी समय-संबंधी तत्व एक केंद्रीय घड़ी द्वारा नियंत्रित होते हैं। ऊपर दिए गए कोड स्निपेट में सबसे महत्वपूर्ण हिस्सा है step_duration=pd.Timedelta("1h"), जो परिभाषित करता है कि घड़ी 1 घंटे के कदमों में बढ़ेगी।
अगले चरण में, आप सर्कस में person आबादी जोड़ते हैं। एक आबादी मूल रूप से ऐसे एजेंटों का समूह है जिनके पास एक id और कुछ विशेषताएँ होती हैं।
प्रत्येक विशेषता के मानों को मैन्युअल रूप से निर्दिष्ट करना संभव है, लेकिन अधिकतर मामलों में, आप उन्हें रैंडमली जेनरेट करना चाहेंगे, इसलिए पहले उसके लिए कुछ generators परिभाषित करते हैं:
from trumania.core.random_generators import SequencialGenerator, FakerGenerator, NumpyRandomGenerator
id_gen = SequencialGenerator(prefix="PERSON_")
age_gen = NumpyRandomGenerator(method="normal", loc=3, scale=5,
seed=next(example_circus.seeder))
name_gen = FakerGenerator(method="name", seed=next(example_circus.seeder))
एक Trumania जेनरेटर तब डेटा उपलब्ध कराने के लिए ज़िम्मेदार होता है जब उसकी विधि generate() को कॉल किया जाता है। ऊपर के उदाहरण में, id_gen ऐसे स्ट्रिंग्स जेनरेट करेगा जैसे PERSON_0001, PERSON_0002, ... age_gen बार-बार एक नार्मल वितरण से डेटा सैंपल करेगा और name_gen रैंडम लोगों के नाम देगा।
ध्यान दें कि numpy के कोई भी सांख्यिकीय वितरण और कोई भी Faker प्रोवाइडर Trumania में उपलब्ध है, और Trumania को नए प्रोवाइडर्स से आसानी से विस्तृत किया जा सकता है।
अब आप सीक्वेंशियल IDs और दो बुनियादी रैंडम विशेषताओं के साथ 1000 व्यक्तियों की आबादी जोड़ सकते हैं:
person = example_circus.create_population(name="person", size=1000, ids_gen=id_gen)
person.create_attribute("NAME", init_gen=name_gen)
person.create_attribute("AGE", init_gen=age_gen)
परिणाम
आप person.to_dataframe() कॉल करके person आबादी के सभी सदस्यों की बनाई गई विशेषताओं पर एक नज़र डाल सकते हैं।
+-------------------+-----------------+---------+
| | NAME | age |
|-------------------+-----------------+---------|
| PERSON_0000000000 | Amy Berger | 28.588 |
| PERSON_0000000001 | Michael Curry | 28.7499 |
| PERSON_0000000002 | Robert Ramirez | 35.9242 |
| PERSON_0000000003 | Derek Gonzalez | 34.7091 |
| PERSON_0000000004 | Gregory Fischer | 25.6009 |
| PERSON_0000000005 | Erica Walker | 33.9758 |
| PERSON_0000000006 | Bradley Collins | 24.4428 |
| PERSON_0000000007 | James Rodriguez | 34.7835 |
| PERSON_0000000008 | Brandy Padilla | 34.6296 |
| PERSON_0000000009 | Mark Taylor | 38.2286 |
+-------------------+-----------------+---------+
सुझाव: यदि आप इस बुनियादी यूज़र आबादी के लिए पूरा स्क्रिप्ट देखना चाहते हैं, तो यह स्निपेट GitHub पर देखें!
Hello World स्टेटमेंट्स: स्टोरीज़ बनाना
उद्देश्य
इसे थोड़ा और दिलचस्प बनाते हैं और एक story जोड़ते हैं। Trumania में एक स्टोरी मूल रूप से परिदृश्य का वह हिस्सा है जो किसी डायनामिक पहलू को समाहित करता है। जैसे ही सिमुलेटेड घड़ी एक कदम आगे बढ़ती है, हर बार एक स्टोरी निष्पादित होती है।
याद करें कि आपने ऊपर सर्कस में step_duration=pd.Timedelta("1h") सेट किया था, इसलिए इसका अर्थ है कि हर तर्कसंगत घंटे पर प्रत्येक स्टोरी को निष्पादित होने का मौका मिलेगा।
आप एक सरल hello-world स्टोरी बनाएँगे जिसमें ऊपर दी गई person आबादी के सभी सदस्य नियमित रूप से "hello world" संदेश प्रसारित करेंगे।
कैसे करें
story बनाते समय निर्दिष्ट करने का पहला मुख्य पहलू वह आबादी है जो स्टोरी की शुरुआत करती है। इस मामले में, यह person होगी। दूसरा पहलू है timer को परिभाषित करना, जो यह बताता है कि आबादी का प्रत्येक सदस्य कब उस क्रिया को ट्रिगर करता है। फिलहाल, आप उन्हें 1 पर हार्ड-कोड कर रहे हैं, जिसका अर्थ है कि सभी सदस्य हर घड़ी-चरण पर स्टोरी को निष्पादित करेंगे (आप बाद के चरण में अधिक उन्नत टाइमर बनाएँगे):
hello_world = example_circus.create_story(
name="hello_world",
initiating_population=example_circus.populations["person"],
member_id_field="PERSON_ID",
timer_gen=ConstantDependentGenerator(value=1)
)
अभी तक, स्टोरी खाली है इसलिए यह कुछ नहीं करती: आपको इसमें कुछ operations जोड़ने की ज़रूरत है। ऑपरेशंस रैंडम या निर्धारक हो सकते हैं, वे किसी भी आबादी की विशेषता या सर्कस की अन्य स्टेट को पढ़ और अपडेट कर सकते हैं, और साइड-इफेक्ट्स भी कर सकते हैं।
फिलहाल, चलिए दो सरल निर्धारक ऑपरेशंस और एक लॉगर जोड़ते हैं ताकि वास्तव में कुछ लॉग्स मिलें:
hello_world.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
ConstantGenerator(value="hello world").ops.generate(named_as="MESSAGE"),
FieldLogger(log_id="hello")
)
example_circus.clock.ops.timestamp मौजूदा 1 घंटे के समयांतराल के भीतर एक रैंडम टाइमस्टैम्प जेनरेट कर रहा है और ConstantGenerator बस स्थिर हार्ड-कोडेड मान पैदा कर रहा है।
परिणाम
आइए सर्कस को 48 घंटे के सिमुलेटेड समय के लिए चलाएँ:
example_circus.run(
duration=pd.Timedelta("48h"),
log_output_folder="example_scenario",
delete_existing_logs=True
)
यह निम्नलिखित बुनियादी डाटासेट उत्पन्न करेगा, जिसमें प्रत्येक 1000 व्यक्ति ने 2 दिनों में 48 बार "hello world" कहा है।
परिणामी डाटासेट का पहला फ़ील्ड, PERSON_ID, story के member_id_field के अनुरूप है। अन्य दो फ़ील्ड, TIME और MESSAGE, आपकी स्टोरी में रखे गए दो मुख्य ऑपरेशंस के अनुरूप हैं।
+-------+-------------------+---------------------+-------------+
| | PERSON_ID | TIME | MESSAGE |
|-------+-------------------+---------------------+-------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | hello world |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | hello world |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | hello world |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | hello world |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | hello world |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | hello world |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | hello world |
| 7 | PERSON_0000000007 | 2017-01-01 01:24:30 | hello world |
| 8 | PERSON_0000000008 | 2017-01-01 01:01:51 | hello world |
| 9 | PERSON_0000000009 | 2017-01-01 01:41:41 | hello world |
| ... |
| 23990 | PERSON_0000000990 | 2017-01-02 23:33:28 | hello world |
| 23991 | PERSON_0000000991 | 2017-01-02 23:15:26 | hello world |
| 23992 | PERSON_0000000992 | 2017-01-02 23:45:56 | hello world |
| 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | hello world |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | hello world |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | hello world |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | hello world |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | hello world |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | hello world |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | hello world |
+-------+-------------------+---------------------+-------------+
सुझाव: पूरा स्निपेट GitHub पर देखें
Hello World सुनने वाला कोई और
उद्देश्य
इसे थोड़ा और बेहतर बनाते हैं और बातचीत में एक और रैंडम व्यक्ति जोड़ते हैं। फिलहाल, आप कहेंगे कि कोई भी व्यक्ति किसी भी अन्य व्यक्ति से समान संभावना के साथ बात कर सकता है, जो बहुत यथार्थपरक नहीं है (आप बाद के चरण में एक सोशल नेटवर्क जोड़ेंगे)। साथ ही, आप लोगों के ID के आधार पर उनके नाम जोड़कर डाटासेट को समृद्ध करेंगे।
कैसे करें
मान लें कि दूसरे व्यक्ति को एक नए OTHER_PERSON फ़ील्ड में संग्रहीत किया जाएगा। इस सरल मामले में, आप बस person आबादी से अनवेटेड रैंडम चयन का परिणाम उस फ़ील्ड में रखना चाहते हैं। आप सरलता से उस आबादी के select_one रैंडम ऑपरेशन का उपयोग कर सकते हैं:
example_circus.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
ConstantGenerator(value="hello world").ops.generate(named_as="MESSAGE"),
example_circus.populations["person"].ops.select_one(named_as="OTHER_PERSON"),
example_circus.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
example_circus.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={"NAME": "RECEIVER_NAME"}),
FieldLogger(log_id="hello")
)
परिणाम
जब आप सर्कस को फिर चलाते हैं, तो आपको नए OTHER_PERSON फ़ील्ड के साथ एक डाटासेट मिलता है:
+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | hello world | PERSON_0000000852 | Ann Cruz | Sophia Black |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | hello world | PERSON_0000000429 | Kimberly Sanchez | Jeffrey Ryan |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | hello world | PERSON_0000000925 | Bethany Smith | Regina Brown |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | hello world | PERSON_0000000347 | Frank Middleton | Jacob Ross |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | hello world | PERSON_0000000211 | Cheryl Decker | Joshua Miller |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | hello world | PERSON_0000000779 | Thomas Rodriguez | Nicole Tanner |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | hello world | PERSON_0000000331 | James Peters | Melissa Rogers |
| 7 | PERSON_0000000007 | 2017-01-01 01:24:30 | hello world | PERSON_0000000234 | Allison Hansen | Taylor Smith |
| 8 | PERSON_0000000008 | 2017-01-01 01:01:51 | hello world | PERSON_0000000678 | Candice Sellers | James Smith |
| 9 | PERSON_0000000009 | 2017-01-01 01:41:41 | hello world | PERSON_0000000108 | Maria White | James Nguyen |
| ... |
| 23990 | PERSON_0000000990 | 2017-01-02 23:33:28 | hello world | PERSON_0000000689 | Natasha Brown | Bailey Ramirez DDS |
| 23991 | PERSON_0000000991 | 2017-01-02 23:15:26 | hello world | PERSON_0000000250 | Shelly Ponce | Jordan Johnson |
| 23992 | PERSON_0000000992 | 2017-01-02 23:45:56 | hello world | PERSON_0000000413 | Steven Mendez | Crystal Duffy |
| 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | hello world | PERSON_0000000670 | Morgan Rice | Jonathan Obrien |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | hello world | PERSON_0000000411 | Crystal Vincent | George Mathis |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | hello world | PERSON_0000000563 | Dawn Kim | Jennifer Martinez |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | hello world | PERSON_0000000668 | Jimmy Franco | Dr. Mark Ruiz MD |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | hello world | PERSON_0000000268 | Christian Christian | Victoria Donovan |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | hello world | PERSON_0000000829 | David Hernandez | Margaret Anderson |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | hello world | PERSON_0000000944 | Tamara Ramirez | Andrew Curtis |
+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+
सुझाव: पूरा कोड आप यहाँ देख सकते हैं
आप तो हमेशा यही कहते हैं
उद्देश्य
आइए इसे और बेहतर बनाते हैं और MESSAGE फ़ील्ड में उबाऊ, हार्ड-कोडेड hello world स्ट्रिंग की जगह एक रैंडम वाक्य जेनरेट करते हैं। इससे आप Trumania के Relationship के पहले बुनियादी उपयोग को दर्शा पाएँगे।
आप प्रत्येक व्यक्ति को 4 उद्धरणों (quotes) से संबद्ध करने जा रहे हैं। जब भी कोई व्यक्ति संदेश प्रसारित करेगा, तो सामग्री उसी व्यक्ति के 4 उद्धरणों में से चुनी जाएगी। इसके अलावा, आप प्रत्येक उद्धरण को एक अलग weight से जोड़ेंगे जो बताता है कि वह उद्धरण कितना संभाव्य है: उच्च वेट वाला उद्धरण अपने मालिक द्वारा कम वेट वाले उद्धरण की तुलना में अधिक बार प्रसारित किया जाएगा।
अब शुरुआत कैसे करें?
कैसे करें
पहला कदम है एक क्वोट जेनरेटर बनाना, जो ऊपर देखे गए अन्य Faker जेनरेटर जैसा ही है:
quote_generator = FakerGenerator(method="sentence", nb_words=6, variable_nb_words=True,
seed=next(example_circus.seeder))
आप उस जेनरेटर का उपयोग पहले की तरह सीधे story में कर सकते थे, लेकिन चलिए चीज़ों को थोड़ा और रोचक बनाते हैं और हर व्यक्ति को हमेशा उसके 4 पसंदीदा उद्धरणों में से ही एक का उपयोग करने के लिए बाध्य करते हैं। आप यह person आबादी के सदस्यों और कुछ वाक्य मानों के बीच एक Relationship बनाकर करते हैं।
पहले, आप एक खाली रिलेशनशिप बनाते हैं:
quotes_rel = example_circus.populations["person"].create_relationship("quotes")
फिर, आप इस रिलेशनशिप को प्रत्येक व्यक्ति के लिए 4 उद्धरणों से भरते हैं। नीचे के कोड में person.ids 1000 आकार की pandas Series है जिसमें person आबादी के सभी IDs हैं, और quote_generator.generate(size=person.size) भी 1000 आकार की एक अन्य pandas Series देता है, जिसमें रैंडम उद्धरण होते हैं।
इसका मतलब है कि नीचे दिए गए for-लूप का प्रत्येक पास रिलेशनशिप में 1000 रिलेशन्स भरता है: 1000 यूज़र्स में से प्रत्येक में एक क्वोट जोड़ता है। पहले 1000 उद्धरणों को weight=1 के साथ संबद्ध किया जाएगा, अगले को weight=2 के साथ अधिक बार आने योग्य बनाया जाएगा, ...
for w in range(4):
quotes_rel.add_relations(
from_ids=person.ids,
to_ids=quote_generator.generate(size=person.size),
weights=w
)
अब आप अपनी स्टोरी में ConstantGenerator को उस रिलेशनशिप पर select_one ऑपरेशन से बदल सकते हैं। इसका अर्थ कुछ यूँ है: हर उस मान के लिए जो वर्तमान में PERSON_ID फ़ील्ड में है, उस ID से शुरू होने वाली quotes रिलेशनशिप देखें और संबंधित मानों में से एक को रैंडम रूप से चुनें। चूँकि नीचे दिए गए ऑपरेशन में कोई वेट ओवरराइड नहीं किया गया है, इसलिए ऊपर add_relations में परिभाषित डिफ़ॉल्ट रिलेशनशिप वेट्स का उपयोग किया जाएगा:
example_circus.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
example_circus.populations["person"].get_relationship("quotes")
.ops.select_one(from_field="PERSON_ID", named_as="MESSAGE"),
example_circus.populations["person"].ops.select_one(named_as="OTHER_PERSON"),
example_circus.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
example_circus.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={"NAME": "RECEIVER_NAME"}),
FieldLogger(log_id="hello")
)
परिणाम
जब आप सर्कस चलाते हैं, तो MESSAGE फ़ील्ड में अब रैंडम क्वोट होना चाहिए:
+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | Become period risk wait now toward less. | PERSON_0000000158 | Ann Cruz | Victoria Washington |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | Month push down. | PERSON_0000000366 | Kimberly Sanchez | Steven Williams |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | Blue general carry else deep problem area. | PERSON_0000000613 | Bethany Smith | Frances Davis |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | Phone sister pretty suddenly allow conference. | PERSON_0000000086 | Frank Middleton | Ashley Fernandez |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | Each discussion several send wide process. | PERSON_0000000972 | Cheryl Decker | Latoya Flynn |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | Guess can issue writer. | PERSON_0000000030 | Thomas Rodriguez | Lindsay Bailey |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | Boy step claim camera common but our. | PERSON_0000000548 | James Peters | Thomas Ward |
| ... | 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | May course and kill from news. | PERSON_0000000202 | Morgan Rice | Patricia Williams |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | Water door live hospital together safe. | PERSON_0000000268 | Crystal Vincent | Victoria Donovan |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | Stage control management read although thousand. | PERSON_0000000466 | Dawn Kim | Ashley Baxter |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | Their that region majority break article. | PERSON_0000000620 | Jimmy Franco | Alex Dominguez |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | Lead simple audience response eye. | PERSON_0000000319 | Christian Christian | David Smith |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | Vote man son yeah child. | PERSON_0000000487 | David Hernandez | Joshua Park |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | Answer region wind condition someone bed cover. | PERSON_0000000237 | Tamara Ramirez | Beverly Rodriguez |
+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+
क्वोट्स के लिए उपयोग की गई रिलेशनशिप का अर्थ यह है कि अब बनाए गए डाटासेट के फ़ील्ड्स एक-दूसरे से संबंधित हैं: कुछ वाक्य कुछ यूज़र्स द्वारा अधिक बार उपयोग किए जाते हैं।
सुझाव: पूरा कोड स्निपेट GitHub पर देखें
जो करते हैं वह नहीं, कब करते हैं वह मायने रखता है
उद्देश्य
अब तक, person आबादी का हर सदस्य दिन के हर घंटे में ठीक एक संदेश बना रहा है। इसे थोड़ा और यथार्थपरक बनाते हैं।
Trumania स्टोरी के निष्पादन के समय-आयाम को नियंत्रित करने के लिए 2 अवधारणाओं के संयोजन का उपयोग करता है: activity levels और timer profiles। साथ मिलकर ये किसी विशिष्ट यूज़र और दिन के समय को देखते हुए story को ट्रिगर करने की संभावना तय करते हैं।
कैसे करें
आप story को अपडेट करेंगे और इन दोनों पहलुओं के पैरामीटर्स सेट करेंगे।
पहले, स्टोरी का timer profile बनाते हैं, जो उन क्षणों को नियंत्रित करता है जब अधिक या कम क्रियाएँ ट्रिगर होती हैं। यह प्रोफ़ाइल उस आबादी के सभी सदस्यों के लिए समान होती है जो स्टोरी को ट्रिगर करते हैं।
Trumania में कुछ उपयोगी डिफ़ॉल्ट प्रोफाइल बिल्ट-इन आते हैं, जैसे DefaultDailyTimerGenerator, जो एक वास्तविक प्रोडक्शन डाटासेट में मापे गए दैनिक फोन उपयोग के अनुरूप है:

इसे अपने परिदृश्य में इस प्रकार इंस्टैंशिएट करें:
from trumania.components.time_patterns.profilers import DefaultDailyTimerGenerator
story_timer_gen = DefaultDailyTimerGenerator(
clock=example_circus.clock,
seed=next(example_circus.seeder))
दूसरा, स्टोरी के लिए आबादी के सदस्य का activity स्तर है, जो यह परिभाषित करता है कि प्रत्येक यूज़र उस स्टोरी के भीतर कितना सक्रिय है। आपके पास प्रत्येक सदस्य के लिए अलग स्तर सेट करने की स्वतंत्रता है, जिससे कुछ सदस्य वह क्रिया दूसरों की तुलना में ज़्यादा या कम बार ट्रिगर करेंगे।
यदि आप चाहें तो आप प्रत्येक स्तर मैन्युअल रूप से निर्दिष्ट कर सकते हैं, हालांकि यहाँ आप एक रैंडम जेनरेटर का उपयोग करेंगे जो प्रत्येक आबादी सदस्य को एक activity level सौंपेगा।
पहले, हम प्रति दिन औसतन 3, 10 और 20 ट्रिगर्स वाले तीन activity levels परिभाषित करते हैं:
low_activity = story_timer_gen.activity(n=3, per=pd.Timedelta("1 day"))
med_activity = story_timer_gen.activity(n=10, per=pd.Timedelta("1 day"))
high_activity = story_timer_gen.activity(n=20, per=pd.Timedelta("1 day"))
फिर, आप वास्तविक activity जेनरेटर बना सकते हैं, जो इस बार choice मेथड पर आधारित एक और Numpy जेनरेटर होगा। नीचे दिया गया जेनरेटर आबादी के 20% को low activity, 70% को medium activity और 10% को high activity सौंपेगा:
activity_gen = NumpyRandomGenerator(
method="choice",
a=[low_activity, med_activity, high_activity],
p=[.2, .7, .1],
seed=next(example_circus.seeder))
और अब आप इस टाइमर प्रोफ़ाइल और activity जेनरेटर का अपनी स्टोरी में उपयोग कर सकते हैं:
hello_world = example_circus.create_story(
name="hello_world",
initiating_population=example_circus.populations["person"],
member_id_field="PERSON_ID",
timer_gen=story_timer_gen,
activity_gen=activity_gen
)
परिणाम
परिणामी डाटासेट का स्कीमा पहले जैसा ही है:
+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------|
| 0 | PERSON_0000000016 | 2017-01-01 00:14:12 | Still try sex sure. | PERSON_0000000739 | Johnny Moore | Adam Barrett |
| 1 | PERSON_0000000063 | 2017-01-01 00:23:51 | Resource magazine wide. | PERSON_0000000511 | Cody Pham | Tina Simmons |
| 2 | PERSON_0000000064 | 2017-01-01 00:37:11 | Heat sure simple letter better forget. | PERSON_0000000044 | Katherine Fleming | Angela Gray |
| 3 | PERSON_0000000076 | 2017-01-01 00:33:12 | Star our conference always place ball. | PERSON_0000000959 | Benjamin Reese II | Barbara Alexander |
| 4 | PERSON_0000000088 | 2017-01-01 00:08:02 | Hot event five left become time commercial. | PERSON_0000000000 | Zachary Cook | Ann Cruz |
| ... |
| 28556 | PERSON_0000000962 | 2017-01-04 00:07:45 | Then include rock rule scientist condition. | PERSON_0000000448 | Johnny Washington | Melissa Adams |
| 28557 | PERSON_0000000980 | 2017-01-04 00:04:44 | Collection full argue interview property pattern never. | PERSON_0000000731 | James Ramirez | David Morrow |
| 28558 | PERSON_0000000983 | 2017-01-04 00:23:21 | High day prepare see. | PERSON_0000000509 | Evan Horne | Robert Sims |
| 28559 | PERSON_0000000988 | 2017-01-04 00:43:56 | Likely south school result case federal seat. | PERSON_0000000819 | Benjamin Campbell | Michelle Jackson DDS |
+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+
सुझाव: स्निपेट GitHub पर देखें
परिणाम विश्लेषण
आपके परिदृश्य के कॉन्फ़िगरेशन में शामिल समय पैटर्न अब परिणामी डाटासेट की आंतरिक संरचना में दिखाई देने चाहिए। आप इसे resulting_dataset पर एक बुनियादी डेटा विश्लेषण करके दिखा सकते हैं:
- दिन के प्रत्येक घंटे पर संदेशों की संख्या निर्दिष्ट वितरण का पालन करनी चाहिए (ध्यान दें कि यह ऊपर के
DefaultDailyTimerGeneratorकी वक्र से कितनी मिलती-जुलती है):
time_profile = (
resulting_dataset[["MESSAGE", "TIME"]]
.groupby(by=example_5_df.TIME.dt.hour)["MESSAGE"]
.count()
)
time_profile.plot()

- प्रति यूज़र संदेशों की संख्या का हिस्टोग्राम भी आपकी कॉन्फ़िगरेशन का सम्मान करना चाहिए:
- आपने
low_activityको औसतन 3 संदेश/दिन,med_activityको 10 औरhigh_activityको 20 पर कॉन्फ़िगर किया और सिमुलेशन 5 दिनों तक चलाया। इससेpersonके 3 समूह होने चाहिए जिनमें क्रमशः लगभग 15, 50 और 100 कुल संदेश हों, जो नीचे दिए हिस्टोग्राम के 3 केंद्रों के अनुरूप है - आपने इन activity levels की संभावनाएँ .2, .7 और .1 निर्धारित कीं, और यह फिर से हिस्टोग्राम के प्रत्येक "बंप" के सापेक्ष क्षेत्र के अनुरूप है:
- आपने
usage_per_user = resulting_dataset[["MESSAGE", "PERSON_ID"]].groupby("PERSON_ID")["MESSAGE"].count()
usage_per_user.plot(kind="hist")

सोशल नेटवर्क
उद्देश्य
आप परिदृश्य को और बेहतर बना सकते हैं, लोगों को इस तरह जोड़कर कि वे आपकी स्टोरी के निष्पादन के दौरान किसी रैंडम व्यक्ति को नहीं बल्कि अपने दोस्तों को संदेश भेजें। इससे परिणामी डाटासेट में बहुत संरचना आ जाएगी क्योंकि अब संदेश लॉग से सामाजिक ग्राफ़ का पता लगाया जा सकेगा।
कैसे करें
आप सोशल नेटवर्क को फिर से एक Relationship से मॉडल कर सकते हैं, जो वही अवधारणा है जिसे आपने ऊपर क्वोट्स मॉडल करने के लिए उपयोग किया था। आपको याद होगा कि quotes रिलेशनशिप में एक weight था। वह वेट किसी व्यक्ति के संदर्भ में कौन-सा क्वोट अधिक या कम संभाव्य है, यह परिभाषित करता था। आप यहाँ भी वही कर सकते हैं और किन दोस्तों को दूसरों की तुलना में अधिक या कम संभावना से कॉल किया जाएगा, यह वेट्स से परिभाषित कर सकते हैं।
ध्यान दें कि यहाँ आप person से person तक रिलेशनशिप परिभाषित कर रहे हैं, जबकि सामान्य रूप से Trumania आपको किसी भी आबादी के जोड़े के बीच रिलेशनशिप परिभाषित करने की सुविधा देता है।
सोशल ग्राफ के एजेस उत्पन्न करने के कई तरीके हैं। एक बुनियादी और क्लासिक तरीका है Erdos-Renyi एल्गोरिद्म पर निर्भर करना। यह Trumania में विशेष रूप से आसान है क्योंकि यह पहले से ही फ्रेमवर्क में शामिल है। आपको बस इसे अपने परिदृश्य में इंजेक्ट करके एक रिलेशनशिप बनानी है।
यहाँ, आप person रिलेशनशिप के सदस्यों के बीच एक सोशल ग्राफ परिभाषित करेंगे जिसमें प्रत्येक व्यक्ति के 20 दोस्त होंगे। ध्यान दें कि इस रिलेशनशिप में स्वतः ही एक Pareto वितरण के साथ एक वेट जोड़ दिया जाएगा।
from trumania.components.social_networks.erdos_renyi import WithErdosRenyi
# self is the circus here, see example code on github for details
self.add_er_social_network_relationship(
self.populations["person"],
relationship_name="friends",
average_degree=20)
इस रिलेशनशिप के साथ, आप अपनी स्टोरी को फिर से देख सकते हैं। इस बार, OTHER_PERSON अब आबादी में से रैंडम नहीं चुना जाएगा, बल्कि प्रत्येक person सदस्य के दोस्तों में से चुना जाएगा, जिसकी संभावना सोशल नेटवर्क में परिभाषित वेट के आनुपातिक होगी:
hello_world.set_operations(
self.clock.ops.timestamp(named_as="TIME"),
self.populations["person"].get_relationship("quotes")
.ops.select_one(from_field="PERSON_ID",named_as="MESSAGE"),
self.populations["person"]
.get_relationship("friends")
.ops.select_one(from_field="PERSON_ID", named_as="OTHER_PERSON"),
self.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
self.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={"NAME": "RECEIVER_NAME"}),
operations.FieldLogger(log_id="hello_6")
)
परिणाम
एक बार फिर, परिणामी डाटासेट का डेटा स्कीमा पहले जैसा ही है, हालाँकि इस बार आपके बुनियादी सोशल नेटवर्क के कारण इसमें पहले से भी अधिक संरचना है:
+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------|
| 0 | PERSON_0000000004 | 2017-01-01 00:14:12 | Clearly see sure. | PERSON_0000000321 | Cheryl Decker | Ian White |
| 1 | PERSON_0000000012 | 2017-01-01 00:23:51 | Offer or interview clear structure watch capital. | PERSON_0000000697 | Kelly Green | Ashley Turner |
| 2 | PERSON_0000000018 | 2017-01-01 00:37:11 | Recently race draw thousand around ahead. | PERSON_0000000989 | Laura Stephenson | Hannah James |
| 3 | PERSON_0000000040 | 2017-01-01 00:33:12 | To protect man image power beyond. | PERSON_0000000418 | Jeffrey Miller | Scott Collins |
... |
| 28966 | PERSON_0000000985 | 2017-01-04 00:09:23 | However agreement fear door land hotel. | PERSON_0000000211 | Laura Mason | Joshua Miller |
| 28967 | PERSON_0000000995 | 2017-01-04 00:48:08 | Top heat window quite forward friend somebody. | PERSON_0000000171 | Dawn Kim | Sandra Phillips |
| 28968 | PERSON_0000000999 | 2017-01-04 00:58:46 | Answer region wind condition someone bed cover. | PERSON_0000000252 | Tamara Ramirez | Jordan Collins |
+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+
सुझाव: आप GitHub पर स्निपेट देख सकते हैं
परिणाम विश्लेषण
उस सोशल नेटवर्क को देखने का एक बहुत ही सरल तरीका है प्रत्येक व्यक्ति द्वारा कॉल किए गए यूनिक दोस्तों की संख्या गिनना। यदि आप सिमुलेशन को पर्याप्त समय तक चलाते हैं, तो यह प्रत्येक व्यक्ति के सोशल नेटवर्क में वास्तविक लोगों की संख्या की एक निचली सीमा देनी चाहिए (क्योंकि आप Pareto वितरण के साथ वेट्स का उपयोग करते हैं, कई लोगों के ऐसे दोस्त होते हैं जिन्हें कॉल किए जाने की संभावना वास्तव में बहुत कम होती है, इसलिए हर संभावित कॉल किए जाने वाले व्यक्ति को देखने के लिए आपको सिमुलेशन को बहुत लंबे समय तक चलाने की आवश्यकता होगी)।
आपने हमारा परिदृश्य 15 सिमुलेटेड दिनों के लिए चलाया और यह प्राप्त किया, जो आपके सोशल ग्राफ में निर्धारित औसत डिग्री 20 के बहुत करीब और उससे थोड़ा कम केंद्रित है:
social_group_size = (
resulting_dataset[["PERSON_ID", "OTHER_PERSON"]]
.groupby("PERSON_ID")
.agg(lambda friends_ids: len(friends_ids.unique()))
)
social_group_size.plot(kind="hist")

और भी बहुत कुछ!
Trumania की कई विशेषताएँ इस पोस्ट में वर्णित नहीं की गई हैं:
- किसी परिदृश्य में कई आबादियाँ होना
- किसी परिदृश्य में कई स्टोरीज़ होना
- स्टोरीज़ के बीच प्रायिकतामूलक निर्भरताएँ जोड़ना (जैसे, किसी व्यक्ति का कॉल किए जाने के बाद दोस्त को कॉल करना)
- स्टेट अपडेट (जैसे, फोन कॉल अवधि के आधार पर बैलेंस खातों को घटाना)
- पुन: उपयोग योग्य परिदृश्य हिस्से, जैसे भौगोलिक क्षेत्र, अधिक टाइमर प्रोफाइल, ...
- परिदृश्य के हिस्सों की स्थायित्व (persistence)
निष्कर्ष
हमने Python में एक परिदृश्य-आधारित डेटा जेनरेटर लाइब्रेरी के रूप में Trumania का परिचय दिया। बनाए गए डाटासेट्स का उपयोग परीक्षण, सीखने और बेंचमार्किंग जैसी व्यापक उपयोगिताओं के लिए किया जा सकता है।
हमने समझाया कि किसी एप्लिकेशन या एल्गोरिद्म का सही तरीके से परीक्षण करने के लिए, हमें ऐसे डाटासेट्स की आवश्यकता होती है जो कुछ अपेक्षित सांख्यिकीय गुणों का पालन करें। हमने दर्शाया कि Trumania ऐसा करने में सक्षम है, एक उदाहरण में जहाँ हमने एक बुनियादी "message log" डाटासेट बनाया जो प्रति यूज़र संदेशों की संख्या के वितरण, दिन के समय के वितरण और एक सोशल ग्राफ में कॉल्स के वितरण का पालन करता है।
हमें आशा है कि हमने यह भी दिखाया कि Trumania के कॉम्पोनेंट्स की लचीलापन व्यापक प्रकार के परिदृश्यों का निर्माण करने की अनुमति देता है।
एक Trumania परिदृश्य एंटिटीज़ के बीच संबंधों को शामिल कर सकता है और इसे सैद्धांतिक रैंडम वितरणों, किसी वास्तविक डाटासेट में देखे गए अनुभवजन्य वितरणों या यहाँ तक कि वास्तविक प्रोडक्शन डेटा (जैसे लोकेशन IDs के डाटासेट) के साथ कॉन्फ़िगर किया जा सकता है। हमने इसे अपने स्टोरी के टाइम रैंडम टाइमर को कॉन्फ़िगर करने के लिए वास्तविक डाटासेट में देखे गए फोन उपयोग टाइमस्टैम्प के सांख्यिकीय वितरण को पुन: उपयोग करके प्रदर्शित किया।
अब जब यह सब स्पष्ट है, तो आगे बढ़ें! Trumania के GitHub पर जाएँ और अपना खुद का परिदृश्य लिखें ;)
अन्यथा, बेझिझक Svend Vanderveken या सह-लेखक Milan van der Meer से संपर्क करें:
- Svend Vanderveken एक फ्रीलांस सॉफ्टवेयर इंजीनियर हैं जिन्हें डेटा-प्रोसेसिंग समाधानों, विशेष रूप से Kafka, Scala, SQL, python... में विशेषज्ञता है। उन्हें उनके ब्लॉग svend.kelesia.com और ट्विटर @sv3ndk पर फ़ॉलो करें।
- Milan van der Meer वर्तमान में Real Impact Analytics में एक सॉफ्टवेयर इंजीनियर के रूप में काम करते हैं। आप उनसे LinkedIn पर हमेशा संपर्क कर सकते हैं