Ana içeriğe geç

Trumania ile Gerçekçi Rastgele Veri Kümeleri Üretme

Senaryo tabanlı rastgele veri kümesi üretici kütüphanesi Python Trumania’yı keşfedin. Bu adım adım eğitimde sentetik ve rastgele bir veri kümesinin nasıl üretileceğini öğrenin.
· 15 dk. oku

Yapay Zeka ile Keşfedin

Editörün notu: Bu yazı Milan van der Meer ile işbirliği içinde yazılmıştır. Her iki yazar da telekom verilerindeki değeri "big data’yı uygulamaya dönüştürerek" ortaya çıkaran yenilikçi Belçikalı büyük veri girişimi Real Impact Analytics ekibindedir.

Bu eğitim, neden rastgele veri kümeleri üretmek isteyebileceğinize ve onlardan ne beklemeniz gerektiğine dair küçük bir fikir verir. Ayrıca, bir veri üretim Python kütüphanesi olan Trumania’yı nasıl kullanacağınıza ilişkin ilk örneklerde size yol gösterecektir.

Daha fazla bilgi için Trumania'nın GitHub sayfasını ziyaret edebilirsiniz!

Neden rastgele veri kümeleri üretmeli?

Rastgele veri kümesi üretimi hem veri mühendisleri hem de veri bilimciler için önemlidir. Veri bilimciler ve veri mühendisleri neden sentetik verilerle çalışır ve bunları nasıl elde eder?

Bir veri mühendisi olarak, yeni harika veri işleme uygulamanızı yazdıktan sonra, uçtan uca testlere başlamanın zamanı geldiğini düşünürsünüz ve bu nedenle bazı giriş verilerine ihtiyaç duyarsınız.

Bir veri bilimci olarak, veri üretimi; veri kümelerini keşfetmenin çeşitli yollarını, algoritmaları, veri görselleştirme tekniklerini denemenize veya seçtiğiniz pek çok farklı veri kümesine karşı bazı yöntemlerin davranışına ilişkin varsayımları doğrulamanıza olanak tanır.

Her iki durumda da, cazip bir seçenek gerçek verileri kullanmaktır. Ancak küçük bir sorun var: üretim verilerine, kısmen dahi olsa, genellikle erişmek zordur ve gizlilik ve güvenlikle ilgili yeni Avrupa yasalarıyla bu daha da zorlaşıyor.

Belki de şanslılardansınız ve dizüstü bilgisayarınızda güzel, eksiksiz bir üretim veri kümesi var. Yine de, farklı nüfus boyutları, farklı veri dağılımları, eksik veya geçersiz veri gibi çeşitli veri kalitesi sorunları gibi farklı durumlara karşı doğrulama yapmak için veri kümesinde daha fazla çeşitlilik istersiniz...

Rastgele veri kümeleri üretmenin neden faydalı olduğuna dair daha kapsamlı bir okuma için 'Sentetik veriler neden yakında büyük bir rekabet avantajına dönüşecek' başlıklı yazıya göz atın.

Şemaya Dayalı Rastgele Veri Üretimi: İyi İlişkilere İhtiyacımız Var!

Bu bölüm, şemaya dayalı rastgele veri üretimini örneklerle anlatır ve kısıtlarını gösterir.

Rastgele veri kümeleri üretmek için hâlihazırda pek çok araç var. Bu araçlar arasında yaygın bir yaklaşım, bir plan tanımlayıp onu kullanarak bazı varlıklar üretmenizi sağlayan şemaya dayalı üretimdir. Khermes ve LogSynth bu tür araçlara iki örnektir.

Şemaya dayalı bir yapılandırma örneği şöyle bir kişi şemasını içerebilir:

{
  {
    "field": "Name",
    "class": NameGenerator
  },
  {
    "field": "Age",
    "class": RandomInt(18, 65)
  },
  {
    "field": "Gender",
    "class": RandomPicker(["Male", "Female", "Other"])
  } 
}

Bu şema bir kişiye ilişkin bazı verilerin üretimini tanımlar. Bir ad, yaş ve cinsiyet içerir. Basittir, hızlıdır ancak bazı sınırlamaları vardır. Başlıca sınırlamalardan biri, farklı varlıklar arasındaki veya zamana dayalı ilişkileri taklit etmektir.

Örneğin, bazı isimleri cinsiyete göre daha olası nasıl yaparsınız? Ya da kullanıcı eylemlerinin hafta sonlarında daha olası olduğu bir eylem günlüğünü nasıl oluşturursunuz?

Şemaya dayalı yaklaşım, yeni uygulamanızı aşağıdakiler gibi gerçek dünya özellikleri veya zorluklarıyla karşılaştırmayı kolaylaştırmaz:

  • Dengesiz veri kümeleri (gruplama türü işlemlerde zorluklar);
  • Varlık ağında kümelenmiş örüntüler. Yani kullanıcı etkileşimleri (örneğin telefon görüşmeleri) üzerinden sosyal grupları keşfetmek;
  • Çeşitli zaman etkinliği profilleri. Eylemler günün veya haftanın belirli zamanlarında daha olasıdır;
  • Eylemler arasında nedensel ilişki. Örneğin, bir mağazada çok sayıda satın alma eylemi sonunda bir "stok tükendi" olayını tetikler.

Trumania, bu eksikleri gidermek ve daha gerçekçi veri kümeleri üretmek için senaryoya dayanır. Senaryo ilerledikçe, çeşitli popülasyonlar birbirleriyle etkileşime girer, özelliklerini günceller ve günlükler üretir.

Bir senaryo örneği, insanların arkadaşlarını araması olabilir. Bir kişi arama yaptığında dakikalar üzerinden ödeme yapar, dakikalar bittiğinde bir mağazaya gitmesi gerekir... Ortaya çıkan veri kümesi kullanıcı arama günlüğü, alışveriş eylemleri günlüğü ve her saat için stok seviyesi olabilir. Bir senaryodaki eylemler rastgele veya deterministik olabilir.

Trumania’da, üretilen veri kümeleri genellikle zaman serileridir; çünkü zaman içinde ilerleyen bir senaryonun yürütülmesiyle oluşurlar.

Trumania ile Birbirine Bağlı Veri Üretimi (Eğitim Zamanı!)

Aşağıdaki örnekte, çeşitli insanların birbirlerine mesaj gönderdiği temel bir senaryoyu nasıl genişletebileceğinizi göreceksiniz. Ortaya çıkan veri kümesi, insanlar arasında değiş tokuş edilen mesajların zaman serisi olacaktır.

İzleyeceğimiz adımlar şunlardır:

  • senaryonun çalışacağı dünyanın içinde yer aldığı Trumania circus’unu oluşturmak
  • temel, sabit kodlu günlükler üretecek bir "hello world" hikâyesi eklemek
  • mesajların içeriğini oluşturmak için kullanılacak, her kişiye bazı favori alıntılar atamak üzere bir relationship eklemek
  • günün geneline daha gerçekçi bir mesaj dağılımı elde etmek için hikâyenin zaman parametrelerini yapılandırmak
  • mesaj günlüğünden ortaya çıkan sosyal grafiğin daha gerçekçi olması için bir sosyal ağ tanımlamak üzere başka bir relationship eklemek

Trumania Circus Oluşturma

Amaç

İlk adım, senaryodaki tüm unsurların var olacağı bir circus oluşturmaktır. Ayrıca temel bir persons popülasyonu yaratacağız. Trumania’nın birçok yönü rastgele olduğundan, bu adımda pek çok rastgele davranışı kontrol etmek için kullanılan generators kavramını da tanıtacağız.

Bu noktada herhangi bir senaryo eklemeyeceğiz; dolayısıyla her şey statik olacak.

Haydi başlayalım!

Nasıl yapılır

Bir Trumania circus’u basitçe şöyle oluşturulur:

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’da, zamanla ilgili tüm unsurlar merkezi bir saat tarafından kontrol edilir. Yukarıdaki kod parçasındaki en önemli bölüm, saatin 1 saatlik adımlarla artırılacağını tanımlayan step_duration=pd.Timedelta("1h") ifadesidir.

Sırada, circus’a person popülasyonunu eklemek var. Bir popülasyon, özünde bir id’ye ve bazı özniteliklere sahip ajanlar kümesidir.

Her özniteliğin değerlerini elle belirtmek mümkündür, ancak çoğu durumda bunları rastgele üretmek istersiniz; bu nedenle bunun için önce birkaç generators tanımlayalım:

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))

Bir Trumania generator’ü, generate() yöntemi çağrıldığında veri sağlamaktan sorumludur. Yukarıdaki örnekte id_gen, PERSON_0001, PERSON_0002, ... gibi dizgiler üretecek; age_gen normal dağılımdan tekrar tekrar örnekleyecek ve name_gen rastgele kişi adları sağlayacaktır.

numpy’daki herhangi bir istatistiksel dağılımın yanı sıra herhangi bir Faker sağlayıcısının Trumania’da mevcut olduğunu ve Trumania’nın yenileriyle kolayca genişletilebileceğini unutmayın.

Artık, sıralı kimliklere ve iki temel rastgele özniteliğe sahip 1000 kişilik bir popülasyon ekleyebilirsiniz:

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)

Sonuç

person popülasyonunun tüm üyelerinin oluşturulan özniteliklerine person.to_dataframe() çağrısıyla hemen göz atabilirsiniz.

+-------------------+-----------------+---------+
|                   | 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 |
+-------------------+-----------------+---------+

İpucu: Bu temel kullanıcı popülasyonu için tüm betiği görmek isterseniz, Github’daki bu parçaya göz atın!

Hello World İfadeleri: Hikâye Oluşturma

Amaç

Bunu biraz daha ilginç hale getirmek için bir story ekleyelim. Bir Trumania hikâyesi, bazı dinamik yönleri kapsülleyen bir senaryo parçasıdır. Simüle edilen saat her bir adım ilerlediğinde bir hikâye yürütülür.

Yukarıdaki circus’ta step_duration=pd.Timedelta("1h") olarak ayarladığınızı hatırlayın; bu da her mantıksal saatte her hikâyenin çalıştırılma şansı olduğu anlamına gelir.

Yukarıdaki person popülasyonunun tüm üyelerinin düzenli olarak "hello world" mesajı yayınladığı basit bir hello-world hikâyesi oluşturacaksınız.

Nasıl yapılır

Bir story oluştururken belirtmeniz gereken ilk ana unsur, hikâyeyi başlatan popülasyondur. Bu durumda bu person olacak. İkinci unsur ise, popülasyonun her bir üyesinin bu eylemi ne zaman tetiklediğini tanımlayan timer’dır. Şimdilik hepsini 1 olarak sabit kodlayacaksınız; bu da tüm üyelerin her saat adımında hikâyeyi çalıştıracağı anlamına gelir (daha sonra daha ayrıntılı zamanlayıcılar oluşturacaksınız):

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)
)

Şu ana kadar hikâye boş; yani bir şey yapmıyor: ona bazı operations eklemeniz gerekiyor. İşlemler rastgele veya deterministik olabilir; herhangi bir popülasyonun özniteliğini veya circus’taki başka bir durum bilgisini okuyup güncelleyebilir ve hatta yan etkileri olabilir.

Şimdilik iki basit deterministik işlem ve gerçek günlükler almak için bir kayıtçı ekleyelim:

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, mevcut 1 saatlik zaman aralığı içinde rastgele bir zaman damgası üretir ve ConstantGenerator sabit, sabit kodlu değerler üretir.

Sonuç

Circus’u 48 saatlik simüle edilmiş zaman için çalıştıralım:

example_circus.run(
    duration=pd.Timedelta("48h"),
    log_output_folder="example_scenario",
    delete_existing_logs=True
)

Bu, her bir 1000 kişinin 2 gün boyunca 48 kez "hello world" dediği aşağıdaki temel veri kümesini üretmelidir.

Ortaya çıkan veri kümesinin ilk alanı olan PERSON_ID, story’nin member_id_field alanına karşılık gelir. Diğer iki alan olan TIME ve MESSAGE ise hikâyenize koyduğunuz iki ana işleme karşılık gelir.

+-------+-------------------+---------------------+-------------+
|       | 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 |
+-------+-------------------+---------------------+-------------+

İpucu: Tüm parçayı Github’da inceleyin

Hello World Diyecek Birileri

Amaç

Bunu, sohbete rastgele başka bir kişi ekleyerek biraz daha geliştirelim. Şimdilik, herhangi bir kişinin eşit olasılıkla herhangi bir başka kişiyle konuşabileceğini söyleyeceksiniz ki bu pek gerçekçi değil (bir sonraki adımda bir sosyal ağ ekleyeceksiniz). Ayrıca, kimliklerine göre kişilerin adlarını ekleyerek veri kümesini zenginleştireceksiniz.

Nasıl yapılır

Diğer kişinin yeni bir OTHER_PERSON alanında tutulacağını varsayalım. Bu basit durumda, bu alana person popülasyonundan rastgele ve ağırlıksız bir seçimin sonucunu koymak istiyorsunuz. Bunun için o popülasyonun select_one rastgele işlemini kullanabilirsiniz:

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")
)

Sonuç

Circus’u tekrar çalıştırdığınızda, yeni OTHER_PERSON alanına sahip bir veri kümesi elde edersiniz:

+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+
|       | 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      |
+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+

İpucu: Tüm kodu burada görebilirsiniz

Hep Aynı Şeyi Söylüyorsun

Amaç

MESSAGE alanında sıkıcı bir hello world sabit dizgesi yerine rastgele bir cümle üreterek daha da geliştirelim. Bu, Trumania’nın Relationship’inin ilk temel kullanımını göstermeye olanak tanıyacak.

Her kişiyi 4 alıntıyla ilişkilendireceksiniz. Bir kişi her mesaj yayınladığında, içerik o kişinin 4 alıntısından biri arasından seçilecek. Ayrıca, her alıntıyı o alıntının olasılığını tanımlayan farklı bir weight ile ilişkilendireceksiniz: yüksek ağırlıklı bir alıntı sahibi tarafından düşük ağırlıklı bir alıntıya göre daha sık yayınlanacaktır.

Şimdi nasıl başlarsınız?

Nasıl yapılır

İlk adım, yukarıda gördüğünüz diğer Faker generator’lerine benzer bir alıntı üretici oluşturmaktır:

quote_generator = FakerGenerator(method="sentence", nb_words=6, variable_nb_words=True,
                                 seed=next(example_circus.seeder))

Bu generator’ü daha önce olduğu gibi story içinde doğrudan kullanabilirsiniz; ancak işi biraz daha ilginç hâle getirip her kişiyi daima kendi 4 favori alıntısından birini kullanmakla sınırlandıralım. Bunu, person popülasyonunun üyeleri ile bazı cümle değerleri arasında bir Relationship oluşturarak yaparsınız.

Önce boş bir relationship oluşturursunuz:

quotes_rel = example_circus.populations["person"].create_relationship("quotes")

Ardından, bu ilişkiyi her kişi için 4 alıntıyla doldurursunuz. Aşağıdaki kodda person.ids, person popülasyonundaki tüm kimlikleri içeren, boyutu 1000 olan bir pandas Series’idir ve quote_generator.generate(size=person.size) yine boyutu 1000 olan, rastgele alıntılar içeren başka bir pandas Series sağlar.

Bu, aşağıdaki döngünün her geçişinin relationship’e 1000 ilişki eklediği anlamına gelir: 1000 kullanıcının her birine bir alıntı eklemek. İlk 1000 alıntı weight=1 ile ilişkilendirilecek, bir sonraki geçiştekiler weight=2 ile daha sık yapılacak, ...

for w in range(4):
    quotes_rel.add_relations(
        from_ids=person.ids,
        to_ids=quote_generator.generate(size=person.size),
        weights=w
    )

Artık hikâyenizdeki ConstantGenerator’ü bu relationship üzerinde bir select_one işlemiyle değiştirebilirsiniz. Bu şu şekilde okunur: PERSON_ID alanında hâlen bulunan her değer için, o kimlikten başlayan quotes ilişkilerini arayın ve rastgele bir ilişkili değer seçin. Aşağıdaki işlemde hiçbir weight geçersiz kılınmadığından, add_relations içinde yukarıda tanımlanan varsayılan ilişki weight’leri kullanılır:

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")
)

Sonuç

Circus’u çalıştırdığınızda, MESSAGE alanı artık rastgele alıntıyı içermelidir:

+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+
|       | 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   |
+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+

Alıntılar için kullanılan relationship’in amacı, artık üretilen veri kümesinin alanlarının ilişkili olmasıdır: bazı cümleler bazı kullanıcılar tarafından daha sık kullanılır.

İpucu: tüm kod parçasını Github’da görüntüleyin

Ne Yaptığın Değil, Ne Zaman Yaptığın

Amaç

Şimdiye kadar, person popülasyonunun her üyesi günün her saatinde tam olarak bir mesaj üretiyordu. Bunu biraz daha gerçekçi yapalım.

Trumania, bir hikâyenin yürütülmesinin zaman boyutunu kontrol etmek için iki kavramın birleşimini kullanır: etkinlik düzeyleri ve zamanlayıcı profilleri. Birlikte, belirli bir kullanıcı ve günün belirli bir saati için story’yi tetikleme olasılığını belirlerler.

Nasıl yapılır

story’yi güncelleyecek ve bu iki unsuru yapılandıracaksınız.

Önce, daha çok ya da daha az eylemin tetiklendiği anları kontrol eden hikâyenin zamanlayıcı profilini oluşturalım. Bu profil, hikâyeyi tetikleyen popülasyonun tüm üyeleri için aynıdır.

Trumania, gerçek bir üretim veri kümesinde ölçtüğümüz günlük telefon kullanımına karşılık gelen DefaultDailyTimerGenerator gibi ilginç bazı varsayılanlarla birlikte gelir:

Trumania Varsayılan Günlük Zamanlayıcı Üreteci Görselleştirmesi

Senaryonuzda bir tane örnekleyelim:

from trumania.components.time_patterns.profilers import DefaultDailyTimerGenerator

story_timer_gen = DefaultDailyTimerGenerator(
    clock=example_circus.clock, 
    seed=next(example_circus.seeder))

İkincisi, bu hikâye için popülasyon üyesinin etkinlik düzeyleridir; bu düzeyler her kullanıcının hikâye içinde ne kadar aktif olduğunu tanımlar. Her üye için farklı bir düzey belirleme özgürlüğüne sahipsiniz; böylece bazı üyeler bu eylemi diğerlerinden daha sık ya da daha seyrek tetikler.

İsterseniz her düzeyi elle belirtebilirsiniz; ancak burada her popülasyon üyesine bir etkinlik düzeyi atayacak rastgele bir generator kullanacaksınız.

Önce, ortalama olarak günde 3, 10 ve 20 tetiklemeden oluşan üç etkinlik düzeyi tanımlıyoruz:

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"))

Ardından, bu kez choice yöntemine dayalı bir Numpy generator’ü olan asıl etkinlik generator’ünü oluşturabilirsiniz. Aşağıdaki generator, popülasyonun %20’sine düşük, %70’ine orta ve %10’una yüksek etkinlik atayacaktır:

activity_gen = NumpyRandomGenerator(
    method="choice", 
    a=[low_activity, med_activity, high_activity],
    p=[.2, .7, .1],
    seed=next(example_circus.seeder))

Ve artık bu zamanlayıcı profilini ve etkinlik generator’ünü hikâyenizin bir parçası olarak kullanabilirsiniz:

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
)

Sonuç

Ortaya çıkan veri kümesinin şeması öncekiyle aynıdır:

+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+
|       | 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 |
+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+

İpucu: parçayı Github’da inceleyin

Sonuç Analizi

Senaryo yapılandırmanıza dâhil ettiğiniz zaman örüntüleri artık ortaya çıkan veri kümesinin iç yapısında görünür olmalıdır. Bunu, ortaya çıkan resulting_dataset üzerinde temel bir veri analizi yaparak gösterebilirsiniz:

  • günün her saatindeki mesaj sayısı, belirtilen dağılımı izlemelidir (yukarıdaki DefaultDailyTimerGenerator eğrisiyle ne kadar benzer olduğuna dikkat edin):
time_profile = (
    resulting_dataset[["MESSAGE", "TIME"]]
    .groupby(by=example_5_df.TIME.dt.hour)["MESSAGE"]
    .count()
)
time_profile.plot()

Trumania Varsayılan Günlük Zamanlayıcı Üreteci Görselleştirmesi

  • Kullanıcı başına mesaj sayısının histogramı da yapılandırmanıza uygun olmalıdır:
    • low_activity’yi günde ortalama 3 mesaja, med_activity’yi 10’a ve high_activity’yi 20’ye ayarladınız ve simülasyonu 5 gün çalıştırdınız. Bu, aşağıdaki histogramın 3 merkezine karşılık gelen, toplamda kabaca 15, 50 ve 100 mesajlık 3 person grubunu vermelidir
    • bu etkinlik düzeylerinin olasılıklarını .2, .7 ve .1 olarak yapılandırdınız ve bu yine histogramdaki her "tümseğin" göreli alanlarına kabaca karşılık gelir:
usage_per_user = resulting_dataset[["MESSAGE", "PERSON_ID"]].groupby("PERSON_ID")["MESSAGE"].count()
usage_per_user.plot(kind="hist")

Kullanıcı başına mesaj sıklığı histogram görselleştirmesi ve grafiği

Sosyal Ağ

Amaç

Senaryoyu, insanlar hikâyenizin yürütülmesi sırasında rastgele birine değil, arkadaşlarına mesaj gönderecek şekilde bağlayarak daha da geliştirebilirsiniz. Bu, ortaya çıkan veri kümesine çok daha fazla yapı kazandıracaktır; çünkü artık sosyal grafik mesaj günlüğünden keşfedilebilir olmalıdır.

Nasıl yapılır

Sosyal ağı yine bir Relationship ile modelleyebilirsiniz; bu, yukarıda alıntıları modellemek için kullandığınız kavramın aynısıdır. quotes relationship’inde bir weight olduğunu hatırlıyor olabilirsiniz. Bu weight, bir kişi için hangi alıntının daha olası olduğunu tanımlıyordu. Burada da aynı şeyi yapabilir ve hangi arkadaşların diğerlerine göre daha olası olarak aranacağını ağırlıklarla tanımlayabilirsiniz.

Burada person’dan person’a bir ilişki tanımladığınıza dikkat edin; ancak genel olarak Trumania, herhangi iki popülasyon çifti arasında ilişki tanımlamanıza olanak verir.

Bir sosyal grafiğin kenarlarını üretmenin pek çok yolu vardır. Temel ve klasik bir yöntem, basitçe Erdos-Renyi algoritmasına güvenmektir. Bu, Trumania’da özellikle kolaydır; çünkü çerçeveye zaten yerleştirilmiştir. Bir relationship oluşturmak için tek yapmanız gereken onu senaryonuza eklemektir.

Burada, person relationship’indeki üyeler arasında her kişinin 20 arkadaşının bulunduğu bir sosyal grafik tanımlayacaksınız. Bu ilişkiye otomatik olarak bir Pareto dağılımı ile ağırlık ekleneceğine dikkat edin.

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)

Bu relationship hazır olduğunda, hikâyemizi bir kez daha gözden geçirebilirsiniz. Bu kez OTHER_PERSON artık popülasyon arasından rastgele seçilmeyecek; her person üyesinin arkadaşları arasından, sosyal ağda tanımlanan ağırlığa orantılı bir olasılıkla seçilecektir:

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")
)

Sonuç

Bir kez daha, ortaya çıkan veri kümesi öncekiyle aynı veri şemasına sahiptir; ancak bu kez temel sosyal ağınız sayesinde öncekinden bile daha fazla yapıya sahiptir:

+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+
|       | 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   |
+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+

İpucu: Github’daki parçaya göz atabilirsiniz

Sonuç Analizi

Bu sosyal ağa bakmanın çok kaba bir yolu, her kişi tarafından aranan benzersiz arkadaş sayısını saymaktır. Simülasyonu yeterince uzun süre çalıştırırsanız, bu, her kişinin sosyal ağındaki gerçek kişi sayısının alt sınırını verir (Pareto dağılımlı weight’ler kullandığınız için, pek çok kişinin aranmaya gerçekten pek olası olmayan arkadaşları vardır; bu yüzden olası her aranan kişiyi gerçekten gözlemlemek için simülasyonun çok uzun sürmesi gerekir).

Senaryomuzu 15 simüle gün boyunca çalıştırdınız ve sosyal grafiğinizde ayarladığınız 20’lik ortalama dereceye çok yakın ve biraz altında merkezlenen şu sonucu elde ettiniz:

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")

Gözlenen sosyal grup boyutu histogramı

Daha Fazlası Var!

Bu yazıda Trumania’nın birkaç özelliği anlatılmadı:

  • bir senaryoda birden fazla popülasyona sahip olmak
  • bir senaryoda birden fazla hikâyeye sahip olmak
  • hikâyeler arasında olasılıksal bağımlılıklar eklemek (ör. bir kişi arandıktan sonra bir arkadaşını arar)
  • durum güncelleme (ör. telefon görüşmesi süresine bağlı olarak bakiye hesaplarını azaltma)
  • coğrafyalar, daha fazla zamanlayıcı profili gibi yeniden kullanılabilir senaryo parçaları
  • senaryo parçalarının kalıcılığı

Sonuç

Trumania’yı Python’da senaryo tabanlı bir veri üretici kütüphanesi olarak tanıttık. Üretilen veri kümeleri, test etme, öğrenme ve kıyaslama gibi çok çeşitli uygulamalar için kullanılabilir.

Bir uygulamayı veya algoritmayı doğru şekilde test etmek için, bazı beklenen istatistiksel özellikleri karşılayan veri kümelerine ihtiyaç duyduğumuzu açıkladık. Trumania’nın bunu yapabildiğini, kullanıcı başına mesaj sayısı dağılımına, günün saatine göre dağılıma ve bir sosyal grafik içinde çağrı dağılımına uyan temel bir "mesaj günlüğü" veri kümesi ürettiğimiz bir örnekle gösterdik.

Ayrıca, Trumania bileşenlerinin esnekliğinin geniş bir senaryo yelpazesinin oluşturulmasına olanak tanıdığını da göstermeyi umuyoruz.

Bir Trumania senaryosu, varlıklar arasındaki ilişkileri içerebilir ve kuramsal rastgele dağılımlarla, gerçek bir veri kümesinde gözlemlenen ampirik dağılımlarla veya hatta gerçek üretim verileriyle (ör. konum kimlikleri veri kümesi gibi) yapılandırılabilir. Bunu, hikâyemizin zaman rastgele zamanlayıcısını yapılandırmak için gerçek bir veri kümesinde gözlemlenen telefon kullanımı zaman damgası istatistiksel dağılımını yeniden kullanarak gösterdik.

Bunu aklınızda bulundurun ve yaratıcılığınızı konuşturun! Trumania'nın Github sayfasına gidin ve kendi senaryonuzu yazın ;)

Aksi hâlde, Svend Vanderveken veya yazar ortağı Milan van der Meer ile iletişime geçmekten çekinmeyin:

  • Svend Vanderveken, başta Kafka, Scala, SQL, Python olmak üzere veri işleme çözümlerinde uzman bir serbest yazılım mühendisidir. Blogu svend.kelesia.com ve Twitter hesabı @sv3ndk üzerinden kendisini takip edin.
  • Milan van der Meer hâlen Real Impact Analytics’te yazılım mühendisi olarak çalışıyor. Kendisiyle her zaman LinkedIn üzerinden bağlantı kurabilirsiniz.

Editörün notu: Bu yazı Milan van der Meer ile işbirliği içinde yazılmıştır. Her iki yazar da telekom verilerindeki değeri "big data’yı uygulamaya dönüştürerek" ortaya çıkaran yenilikçi Belçikalı büyük veri girişimi Real Impact Analytics ekibindedir.

Bu eğitim, neden rastgele veri kümeleri üretmek isteyebileceğinize ve onlardan ne beklemeniz gerektiğine dair küçük bir fikir verir. Ayrıca, bir veri üretim Python kütüphanesi olan Trumania’yı nasıl kullanacağınıza ilişkin ilk örneklerde size yol gösterecektir.

Daha fazla bilgi için Trumania'nın GitHub sayfasını ziyaret edebilirsiniz!

Neden rastgele veri kümeleri üretmeli?

Rastgele veri kümesi üretimi hem veri mühendisleri hem de veri bilimciler için önemlidir. Veri bilimciler ve veri mühendisleri neden sentetik verilerle çalışır ve bunları nasıl elde eder?

Bir veri mühendisi olarak, yeni harika veri işleme uygulamanızı yazdıktan sonra, uçtan uca testlere başlamanın zamanı geldiğini düşünürsünüz ve bu nedenle bazı giriş verilerine ihtiyaç duyarsınız.

Bir veri bilimci olarak, veri üretimi; veri kümelerini keşfetmenin çeşitli yollarını, algoritmaları, veri görselleştirme tekniklerini denemenize veya seçtiğiniz pek çok farklı veri kümesine karşı bazı yöntemlerin davranışına ilişkin varsayımları doğrulamanıza olanak tanır.

Her iki durumda da, cazip bir seçenek gerçek verileri kullanmaktır. Ancak küçük bir sorun var: üretim verilerine, kısmen dahi olsa, genellikle erişmek zordur ve gizlilik ve güvenlikle ilgili yeni Avrupa yasalarıyla bu daha da zorlaşıyor.

Belki de şanslılardansınız ve dizüstü bilgisayarınızda güzel, eksiksiz bir üretim veri kümesi var. Yine de, farklı nüfus boyutları, farklı veri dağılımları, eksik veya geçersiz veri gibi çeşitli veri kalitesi sorunları gibi farklı durumlara karşı doğrulama yapmak için veri kümesinde daha fazla çeşitlilik istersiniz...

Rastgele veri kümeleri üretmenin neden faydalı olduğuna dair daha kapsamlı bir okuma için 'Sentetik veriler neden yakında büyük bir rekabet avantajına dönüşecek' başlıklı yazıya göz atın.

Şemaya Dayalı Rastgele Veri Üretimi: İyi İlişkilere İhtiyacımız Var!

Bu bölüm, şemaya dayalı rastgele veri üretimini örneklerle anlatır ve kısıtlarını gösterir.

Rastgele veri kümeleri üretmek için hâlihazırda pek çok araç var. Bu araçlar arasında yaygın bir yaklaşım, bir plan tanımlayıp onu kullanarak bazı varlıklar üretmenizi sağlayan şemaya dayalı üretimdir. Khermes ve LogSynth bu tür araçlara iki örnektir.

Şemaya dayalı bir yapılandırma örneği şöyle bir kişi şemasını içerebilir:

{
  {
    "field": "Name",
    "class": NameGenerator
  },
  {
    "field": "Age",
    "class": RandomInt(18, 65)
  },
  {
    "field": "Gender",
    "class": RandomPicker(["Male", "Female", "Other"])
  } 
}

Bu şema bir kişiye ilişkin bazı verilerin üretimini tanımlar. Bir ad, yaş ve cinsiyet içerir. Basittir, hızlıdır ancak bazı sınırlamaları vardır. Başlıca sınırlamalardan biri, farklı varlıklar arasındaki veya zamana dayalı ilişkileri taklit etmektir.

Örneğin, bazı isimleri cinsiyete göre daha olası nasıl yaparsınız? Ya da kullanıcı eylemlerinin hafta sonlarında daha olası olduğu bir eylem günlüğünü nasıl oluşturursunuz?

Şemaya dayalı yaklaşım, yeni uygulamanızı aşağıdakiler gibi gerçek dünya özellikleri veya zorluklarıyla karşılaştırmayı kolaylaştırmaz:

  • Dengesiz veri kümeleri (gruplama türü işlemlerde zorluklar);
  • Varlık ağında kümelenmiş örüntüler. Yani kullanıcı etkileşimleri (örneğin telefon görüşmeleri) üzerinden sosyal grupları keşfetmek;
  • Çeşitli zaman etkinliği profilleri. Eylemler günün veya haftanın belirli zamanlarında daha olasıdır;
  • Eylemler arasında nedensel ilişki. Örneğin, bir mağazada çok sayıda satın alma eylemi sonunda bir "stok tükendi" olayını tetikler.

Trumania, bu eksikleri gidermek ve daha gerçekçi veri kümeleri üretmek için senaryoya dayanır. Senaryo ilerledikçe, çeşitli popülasyonlar birbirleriyle etkileşime girer, özelliklerini günceller ve günlükler üretir.

Bir senaryo örneği, insanların arkadaşlarını araması olabilir. Bir kişi arama yaptığında dakikalar üzerinden ödeme yapar, dakikalar bittiğinde bir mağazaya gitmesi gerekir... Ortaya çıkan veri kümesi kullanıcı arama günlüğü, alışveriş eylemleri günlüğü ve her saat için stok seviyesi olabilir. Bir senaryodaki eylemler rastgele veya deterministik olabilir.

Trumania’da, üretilen veri kümeleri genellikle zaman serileridir; çünkü zaman içinde ilerleyen bir senaryonun yürütülmesiyle oluşurlar.

Aşağıdaki örnekte, çeşitli insanların birbirlerine mesaj gönderdiği temel bir senaryoyu nasıl genişletebileceğinizi göreceksiniz. Ortaya çıkan veri kümesi, insanlar arasında değiş tokuş edilen mesajların zaman serisi olacaktır.

İzleyeceğimiz adımlar şunlardır:

  • senaryonun çalışacağı dünyanın içinde yer aldığı Trumania circus’unu oluşturmak
  • temel, sabit kodlu günlükler üretecek bir "hello world" hikâyesi eklemek
  • mesajların içeriğini oluşturmak için kullanılacak, her kişiye bazı favori alıntılar atamak üzere bir relationship eklemek
  • günün geneline daha gerçekçi bir mesaj dağılımı elde etmek için hikâyenin zaman parametrelerini yapılandırmak
  • mesaj günlüğünden ortaya çıkan sosyal grafiğin daha gerçekçi olması için bir sosyal ağ tanımlamak üzere başka bir relationship eklemek

Trumania Circus Oluşturma

Amaç

İlk adım, senaryodaki tüm unsurların var olacağı bir circus oluşturmaktır. Ayrıca temel bir persons popülasyonu yaratacağız. Trumania’nın birçok yönü rastgele olduğundan, bu adımda pek çok rastgele davranışı kontrol etmek için kullanılan generators kavramını da tanıtacağız.

Bu noktada herhangi bir senaryo eklemeyeceğiz; dolayısıyla her şey statik olacak.

Haydi başlayalım!

Nasıl yapılır

Bir Trumania circus’u basitçe şöyle oluşturulur:

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’da, zamanla ilgili tüm unsurlar merkezi bir saat tarafından kontrol edilir. Yukarıdaki kod parçasındaki en önemli bölüm, saatin 1 saatlik adımlarla artırılacağını tanımlayan step_duration=pd.Timedelta("1h") ifadesidir.

Sırada, circus’a person popülasyonunu eklemek var. Bir popülasyon, özünde bir id’ye ve bazı özniteliklere sahip ajanlar kümesidir.

Her özniteliğin değerlerini elle belirtmek mümkündür, ancak çoğu durumda bunları rastgele üretmek istersiniz; bu nedenle bunun için önce birkaç generators tanımlayalım:

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))

Bir Trumania generator’ü, generate() yöntemi çağrıldığında veri sağlamaktan sorumludur. Yukarıdaki örnekte id_gen, PERSON_0001, PERSON_0002, ... gibi dizgiler üretecek; age_gen normal dağılımdan tekrar tekrar örnekleyecek ve name_gen rastgele kişi adları sağlayacaktır.

numpy’daki herhangi bir istatistiksel dağılımın yanı sıra herhangi bir Faker sağlayıcısının Trumania’da mevcut olduğunu ve Trumania’nın yenileriyle kolayca genişletilebileceğini unutmayın.

Artık, sıralı kimliklere ve iki temel rastgele özniteliğe sahip 1000 kişilik bir popülasyon ekleyebilirsiniz:

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)

Sonuç

person popülasyonunun tüm üyelerinin oluşturulan özniteliklerine person.to_dataframe() çağrısıyla hemen göz atabilirsiniz.

+-------------------+-----------------+---------+
|                   | 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 |
+-------------------+-----------------+---------+

İpucu: Bu temel kullanıcı popülasyonu için tüm betiği görmek isterseniz, Github’daki bu parçaya göz atın!

Hello World İfadeleri: Hikâye Oluşturma

Amaç

Bunu biraz daha ilginç hale getirmek için bir story ekleyelim. Bir Trumania hikâyesi, bazı dinamik yönleri kapsülleyen bir senaryo parçasıdır. Simüle edilen saat her bir adım ilerlediğinde bir hikâye yürütülür.

Yukarıdaki circus’ta step_duration=pd.Timedelta("1h") olarak ayarladığınızı hatırlayın; bu da her mantıksal saatte her hikâyenin çalıştırılma şansı olduğu anlamına gelir.

Yukarıdaki person popülasyonunun tüm üyelerinin düzenli olarak "hello world" mesajı yayınladığı basit bir hello-world hikâyesi oluşturacaksınız.

Nasıl yapılır

Bir story oluştururken belirtmeniz gereken ilk ana unsur, hikâyeyi başlatan popülasyondur. Bu durumda bu person olacak. İkinci unsur ise, popülasyonun her bir üyesinin bu eylemi ne zaman tetiklediğini tanımlayan timer’dır. Şimdilik hepsini 1 olarak sabit kodlayacaksınız; bu da tüm üyelerin her saat adımında hikâyeyi çalıştıracağı anlamına gelir (daha sonra daha ayrıntılı zamanlayıcılar oluşturacaksınız):

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)
)

Şu ana kadar hikâye boş; yani bir şey yapmıyor: ona bazı operations eklemeniz gerekiyor. İşlemler rastgele veya deterministik olabilir; herhangi bir popülasyonun özniteliğini veya circus’taki başka bir durum bilgisini okuyup güncelleyebilir ve hatta yan etkileri olabilir.

Şimdilik iki basit deterministik işlem ve gerçek günlükler almak için bir kayıtçı ekleyelim:

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, mevcut 1 saatlik zaman aralığı içinde rastgele bir zaman damgası üretir ve ConstantGenerator sabit, sabit kodlu değerler üretir.

Sonuç

Circus’u 48 saatlik simüle edilmiş zaman için çalıştıralım:

example_circus.run(
    duration=pd.Timedelta("48h"),
    log_output_folder="example_scenario",
    delete_existing_logs=True
)

Bu, her bir 1000 kişinin 2 gün boyunca 48 kez "hello world" dediği aşağıdaki temel veri kümesini üretmelidir.

Ortaya çıkan veri kümesinin ilk alanı olan PERSON_ID, story’nin member_id_field alanına karşılık gelir. Diğer iki alan olan TIME ve MESSAGE ise hikâyenize koyduğunuz iki ana işleme karşılık gelir.

+-------+-------------------+---------------------+-------------+
|       | 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 |
+-------+-------------------+---------------------+-------------+

İpucu: Tüm parçayı Github’da inceleyin

Hello World Diyecek Birileri

Amaç

Bunu, sohbete rastgele başka bir kişi ekleyerek biraz daha geliştirelim. Şimdilik, herhangi bir kişinin eşit olasılıkla herhangi bir başka kişiyle konuşabileceğini söyleyeceksiniz ki bu pek gerçekçi değil (bir sonraki adımda bir sosyal ağ ekleyeceksiniz). Ayrıca, kimliklerine göre kişilerin adlarını ekleyerek veri kümesini zenginleştireceksiniz.

Nasıl yapılır

Diğer kişinin yeni bir OTHER_PERSON alanında tutulacağını varsayalım. Bu basit durumda, bu alana person popülasyonundan rastgele ve ağırlıksız bir seçimin sonucunu koymak istiyorsunuz. Bunun için o popülasyonun select_one rastgele işlemini kullanabilirsiniz:

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")
)

Sonuç

Circus’u tekrar çalıştırdığınızda, yeni OTHER_PERSON alanına sahip bir veri kümesi elde edersiniz:

+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+
|       | 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      |
+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+

İpucu: Tüm kodu burada görebilirsiniz

Hep Aynı Şeyi Söylüyorsun

Amaç

MESSAGE alanında sıkıcı bir hello world sabit dizgesi yerine rastgele bir cümle üreterek daha da geliştirelim. Bu, Trumania’nın Relationship’inin ilk temel kullanımını göstermeye olanak tanıyacak.

Her kişiyi 4 alıntıyla ilişkilendireceksiniz. Bir kişi her mesaj yayınladığında, içerik o kişinin 4 alıntısından biri arasından seçilecek. Ayrıca, her alıntıyı o alıntının olasılığını tanımlayan farklı bir weight ile ilişkilendireceksiniz: yüksek ağırlıklı bir alıntı sahibi tarafından düşük ağırlıklı bir alıntıya göre daha sık yayınlanacaktır.

Şimdi nasıl başlarsınız?

Nasıl yapılır

İlk adım, yukarıda gördüğünüz diğer Faker generator’lerine benzer bir alıntı üretici oluşturmaktır:

quote_generator = FakerGenerator(method="sentence", nb_words=6, variable_nb_words=True,
                                 seed=next(example_circus.seeder))

Bu generator’ü daha önce olduğu gibi story içinde doğrudan kullanabilirsiniz; ancak işi biraz daha ilginç hâle getirip her kişiyi daima kendi 4 favori alıntısından birini kullanmakla sınırlandıralım. Bunu, person popülasyonunun üyeleri ile bazı cümle değerleri arasında bir Relationship oluşturarak yaparsınız.

Önce boş bir relationship oluşturursunuz:

quotes_rel = example_circus.populations["person"].create_relationship("quotes")

Ardından, bu ilişkiyi her kişi için 4 alıntıyla doldurursunuz. Aşağıdaki kodda person.ids, person popülasyonundaki tüm kimlikleri içeren, boyutu 1000 olan bir pandas Series’idir ve quote_generator.generate(size=person.size) yine boyutu 1000 olan, rastgele alıntılar içeren başka bir pandas Series sağlar.

Bu, aşağıdaki döngünün her geçişinin relationship’e 1000 ilişki eklediği anlamına gelir: 1000 kullanıcının her birine bir alıntı eklemek. İlk 1000 alıntı weight=1 ile ilişkilendirilecek, bir sonraki geçiştekiler weight=2 ile daha sık yapılacak, ...

for w in range(4):
    quotes_rel.add_relations(
        from_ids=person.ids,
        to_ids=quote_generator.generate(size=person.size),
        weights=w
    )

Artık hikâyenizdeki ConstantGenerator’ü bu relationship üzerinde bir select_one işlemiyle değiştirebilirsiniz. Bu şu şekilde okunur: PERSON_ID alanında hâlen bulunan her değer için, o kimlikten başlayan quotes ilişkilerini arayın ve rastgele bir ilişkili değer seçin. Aşağıdaki işlemde hiçbir weight geçersiz kılınmadığından, add_relations içinde yukarıda tanımlanan varsayılan ilişki weight’leri kullanılır:

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")
)

Sonuç

Circus’u çalıştırdığınızda, MESSAGE alanı artık rastgele alıntıyı içermelidir:

+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+
|       | 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   |
+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+

Alıntılar için kullanılan relationship’in amacı, artık üretilen veri kümesinin alanlarının ilişkili olmasıdır: bazı cümleler bazı kullanıcılar tarafından daha sık kullanılır.

İpucu: tüm kod parçasını Github’da görüntüleyin

Ne Yaptığın Değil, Ne Zaman Yaptığın

Amaç

Şimdiye kadar, person popülasyonunun her üyesi günün her saatinde tam olarak bir mesaj üretiyordu. Bunu biraz daha gerçekçi yapalım.

Trumania, bir hikâyenin yürütülmesinin zaman boyutunu kontrol etmek için iki kavramın birleşimini kullanır: etkinlik düzeyleri ve zamanlayıcı profilleri. Birlikte, belirli bir kullanıcı ve günün belirli bir saati için story’yi tetikleme olasılığını belirlerler.

Nasıl yapılır

story’yi güncelleyecek ve bu iki unsuru yapılandıracaksınız.

Önce, daha çok ya da daha az eylemin tetiklendiği anları kontrol eden hikâyenin zamanlayıcı profilini oluşturalım. Bu profil, hikâyeyi tetikleyen popülasyonun tüm üyeleri için aynıdır.

Trumania, gerçek bir üretim veri kümesinde ölçtüğümüz günlük telefon kullanımına karşılık gelen DefaultDailyTimerGenerator gibi ilginç bazı varsayılanlarla birlikte gelir:

Trumania Varsayılan Günlük Zamanlayıcı Üreteci Görselleştirmesi

Senaryonuzda bir tane örnekleyelim:

from trumania.components.time_patterns.profilers import DefaultDailyTimerGenerator

story_timer_gen = DefaultDailyTimerGenerator(
    clock=example_circus.clock, 
    seed=next(example_circus.seeder))

İkincisi, bu hikâye için popülasyon üyesinin etkinlik düzeyleridir; bu düzeyler her kullanıcının hikâye içinde ne kadar aktif olduğunu tanımlar. Her üye için farklı bir düzey belirleme özgürlüğüne sahipsiniz; böylece bazı üyeler bu eylemi diğerlerinden daha sık ya da daha seyrek tetikler.

İsterseniz her düzeyi elle belirtebilirsiniz; ancak burada her popülasyon üyesine bir etkinlik düzeyi atayacak rastgele bir generator kullanacaksınız.

Önce, ortalama olarak günde 3, 10 ve 20 tetiklemeden oluşan üç etkinlik düzeyi tanımlıyoruz:

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"))

Ardından, bu kez choice yöntemine dayalı bir Numpy generator’ü olan asıl etkinlik generator’ünü oluşturabilirsiniz. Aşağıdaki generator, popülasyonun %20’sine düşük, %70’ine orta ve %10’una yüksek etkinlik atayacaktır:

activity_gen = NumpyRandomGenerator(
    method="choice", 
    a=[low_activity, med_activity, high_activity],
    p=[.2, .7, .1],
    seed=next(example_circus.seeder))

Ve artık bu zamanlayıcı profilini ve etkinlik generator’ünü hikâyenizin bir parçası olarak kullanabilirsiniz:

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
)

Sonuç

Ortaya çıkan veri kümesinin şeması öncekiyle aynıdır:

+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+
|       | 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 |
+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+

İpucu: parçayı Github’da inceleyin

Sonuç Analizi

Senaryo yapılandırmanıza dâhil ettiğiniz zaman örüntüleri artık ortaya çıkan veri kümesinin iç yapısında görünür olmalıdır. Bunu, ortaya çıkan resulting_dataset üzerinde temel bir veri analizi yaparak gösterebilirsiniz:

  • günün her saatindeki mesaj sayısı, belirtilen dağılımı izlemelidir (yukarıdaki DefaultDailyTimerGenerator eğrisiyle ne kadar benzer olduğuna dikkat edin):
time_profile = (
    resulting_dataset[["MESSAGE", "TIME"]]
    .groupby(by=example_5_df.TIME.dt.hour)["MESSAGE"]
    .count()
)
time_profile.plot()

Trumania Varsayılan Günlük Zamanlayıcı Üreteci Görselleştirmesi

  • Kullanıcı başına mesaj sayısının histogramı da yapılandırmanıza uygun olmalıdır:
    • low_activity’yi günde ortalama 3 mesaja, med_activity’yi 10’a ve high_activity’yi 20’ye ayarladınız ve simülasyonu 5 gün çalıştırdınız. Bu, aşağıdaki histogramın 3 merkezine karşılık gelen, toplamda kabaca 15, 50 ve 100 mesajlık 3 person grubunu vermelidir
    • bu etkinlik düzeylerinin olasılıklarını .2, .7 ve .1 olarak yapılandırdınız ve bu yine histogramdaki her "tümseğin" göreli alanlarına kabaca karşılık gelir:
usage_per_user = resulting_dataset[["MESSAGE", "PERSON_ID"]].groupby("PERSON_ID")["MESSAGE"].count()
usage_per_user.plot(kind="hist")

Kullanıcı başına mesaj sıklığı histogram görselleştirmesi ve grafiği

Sosyal Ağ

Amaç

Senaryoyu, insanlar hikâyenizin yürütülmesi sırasında rastgele birine değil, arkadaşlarına mesaj gönderecek şekilde bağlayarak daha da geliştirebilirsiniz. Bu, ortaya çıkan veri kümesine çok daha fazla yapı kazandıracaktır; çünkü artık sosyal grafik mesaj günlüğünden keşfedilebilir olmalıdır.

Nasıl yapılır

Sosyal ağı yine bir Relationship ile modelleyebilirsiniz; bu, yukarıda alıntıları modellemek için kullandığınız kavramın aynısıdır. quotes relationship’inde bir weight olduğunu hatırlıyor olabilirsiniz. Bu weight, bir kişi için hangi alıntının daha olası olduğunu tanımlıyordu. Burada da aynı şeyi yapabilir ve hangi arkadaşların diğerlerine göre daha olası olarak aranacağını ağırlıklarla tanımlayabilirsiniz.

Burada person’dan person’a bir ilişki tanımladığınıza dikkat edin; ancak genel olarak Trumania, herhangi iki popülasyon çifti arasında ilişki tanımlamanıza olanak verir.

Bir sosyal grafiğin kenarlarını üretmenin pek çok yolu vardır. Temel ve klasik bir yöntem, basitçe Erdos-Renyi algoritmasına güvenmektir. Bu, Trumania’da özellikle kolaydır; çünkü çerçeveye zaten yerleştirilmiştir. Bir relationship oluşturmak için tek yapmanız gereken onu senaryonuza eklemektir.

Burada, person relationship’indeki üyeler arasında her kişinin 20 arkadaşının bulunduğu bir sosyal grafik tanımlayacaksınız. Bu ilişkiye otomatik olarak bir Pareto dağılımı ile ağırlık ekleneceğine dikkat edin.

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)

Bu relationship hazır olduğunda, hikâyemizi bir kez daha gözden geçirebilirsiniz. Bu kez OTHER_PERSON artık popülasyon arasından rastgele seçilmeyecek; her person üyesinin arkadaşları arasından, sosyal ağda tanımlanan ağırlığa orantılı bir olasılıkla seçilecektir:

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")
)

Sonuç

Bir kez daha, ortaya çıkan veri kümesi öncekiyle aynı veri şemasına sahiptir; ancak bu kez temel sosyal ağınız sayesinde öncekinden bile daha fazla yapıya sahiptir:

+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+
|       | 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   |
+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+

İpucu: Github’daki parçaya göz atabilirsiniz

Sonuç Analizi

Bu sosyal ağa bakmanın çok kaba bir yolu, her kişi tarafından aranan benzersiz arkadaş sayısını saymaktır. Simülasyonu yeterince uzun süre çalıştırırsanız, bu, her kişinin sosyal ağındaki gerçek kişi sayısının alt sınırını verir (Pareto dağılımlı weight’ler kullandığınız için, pek çok kişinin aranmaya gerçekten pek olası olmayan arkadaşları vardır; bu yüzden olası her aranan kişiyi gerçekten gözlemlemek için simülasyonun çok uzun sürmesi gerekir).

Senaryomuzu 15 simüle gün boyunca çalıştırdınız ve sosyal grafiğinizde ayarladığınız 20’lik ortalama dereceye çok yakın ve biraz altında merkezlenen şu sonucu elde ettiniz:

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")

Gözlenen sosyal grup boyutu histogramı

Daha Fazlası Var!

Bu yazıda Trumania’nın birkaç özelliği anlatılmadı:

  • bir senaryoda birden fazla popülasyona sahip olmak
  • bir senaryoda birden fazla hikâyeye sahip olmak
  • hikâyeler arasında olasılıksal bağımlılıklar eklemek (ör. bir kişi arandıktan sonra bir arkadaşını arar)
  • durum güncelleme (ör. telefon görüşmesi süresine bağlı olarak bakiye hesaplarını azaltma)
  • coğrafyalar, daha fazla zamanlayıcı profili gibi yeniden kullanılabilir senaryo parçaları
  • senaryo parçalarının kalıcılığı

Sonuç

Trumania’yı Python’da senaryo tabanlı bir veri üretici kütüphanesi olarak tanıttık. Üretilen veri kümeleri, test etme, öğrenme ve kıyaslama gibi çok çeşitli uygulamalar için kullanılabilir.

Bir uygulamayı veya algoritmayı doğru şekilde test etmek için, bazı beklenen istatistiksel özellikleri karşılayan veri kümelerine ihtiyaç duyduğumuzu açıkladık. Trumania’nın bunu yapabildiğini, kullanıcı başına mesaj sayısı dağılımına, günün saatine göre dağılıma ve bir sosyal grafik içinde çağrı dağılımına uyan temel bir "mesaj günlüğü" veri kümesi ürettiğimiz bir örnekle gösterdik.

Ayrıca, Trumania bileşenlerinin esnekliğinin geniş bir senaryo yelpazesinin oluşturulmasına olanak tanıdığını da göstermeyi umuyoruz.

Bir Trumania senaryosu, varlıklar arasındaki ilişkileri içerebilir ve kuramsal rastgele dağılımlarla, gerçek bir veri kümesinde gözlemlenen ampirik dağılımlarla veya hatta gerçek üretim verileriyle (ör. konum kimlikleri veri kümesi gibi) yapılandırılabilir. Bunu, hikâyemizin zaman rastgele zamanlayıcısını yapılandırmak için gerçek bir veri kümesinde gözlemlenen telefon kullanımı zaman damgası istatistiksel dağılımını yeniden kullanarak gösterdik.

Bunu aklınızda bulundurun ve yaratıcılığınızı konuşturun! Trumania'nın Github sayfasına gidin ve kendi senaryonuzu yazın ;)

Aksi hâlde, Svend Vanderveken veya yazar ortağı Milan van der Meer ile iletişime geçmekten çekinmeyin:

  • Svend Vanderveken, başta Kafka, Scala, SQL, Python olmak üzere veri işleme çözümlerinde uzman bir serbest yazılım mühendisidir. Blogu svend.kelesia.com ve Twitter hesabı @sv3ndk üzerinden kendisini takip edin.
  • Milan van der Meer hâlen Real Impact Analytics’te yazılım mühendisi olarak çalışıyor. Kendisiyle her zaman LinkedIn üzerinden bağlantı kurabilirsiniz.

Konular

İlgili