Coder Social home page Coder Social logo

similarity's Introduction

Metoda tworzenia miar zastępowalności składników przy uwzględnieniu celu zamiany - wersja 1

Wprowadzenie

W niniejszym opracowaniu rozważa się problem opracowania metody definiowania miary zastępowalności składników spożywczych w przepisach kulinarnych zgodnej z wymaganiami zdefiniowanymi przez użytkownika. Zakłada się, że zdefiniowanie jednej miary, która jednocześnie pokryłaby wszystkie możliwe wymagania jest niemożliwe, ponieważ składnik, który w jednym zastosowaniu jest substytutem niebudzącym zastrzeżeń (np. zastępienie schabu polędwicą wieprzową przy braku ograniczeń dietetycznych), w innym będzie nie do przyjęcia (np. zastępienie schabu polędwicą wieprzową w diecie wegańskiej).

W przedstawionej wersji przyjęto następujące założenia:

  • zamianie poddawany jest jeden składnik na raz, a nie grupa składników;
  • wynikiem zamiany jest jeden składnik, a nie grupa składników;
  • nie rozważa się ilości produktów;
  • nie uwzględnia się przepisu, na którego potrzeby dokonywana jest zamiana;
  • miara powinna oferować użytkownikowi wyjaśnialność decyzji, w szczególności unikając złożonych modeli typu czarna skrzynka czy wykorzystywania wektorów zanurzeń;
  • istnieją dwie, zasadniczo różniące się od siebie role: ekspert dziedzinowy, który w ramach przedstawionej metody definiuje niezbędne elementy, żeby uzyskać miarę zastępowalności pod konkretną specyfikację (np. zastępowanie w diecie cukrzycowej), a który ma całą niezbędną wiedzę, żeby ocenić wynik działania systemu oraz użytkownika końcowego, który korzysta z miary zdefiniowanej przez eksperta dziedzinowego i nie posiada niezbędnej wiedzy do oceny działania systemu.

W toku prac zidentyfikowano kilka wymiarów, które mogą wpływać na zamienianie składników. Należy zaznaczyć, że nie jest to lista wyczerpująca ani zakorzeniona w studiach literaturowych. Wymiary, poza wyjaśnieniem, opisane są też wprowadzaną twardością ograniczenia. Wyróżnia się ograniczenie twarde tzn. takie, którego naruszenie powoduje, że potencjalny subsytut jest nieprzydatny z punktu widzenia użytkownika, np. zastąpienie schabu polędwicą wieprzową w diecie wegańskiej; oraz ograniczenie miękkie tzn. takie, które może być lepiej lub gorzej spełnione, np. zastąpienie cukru białego miodem w diecie cukrzycowej. Wskazuje się też czy dana cecha jest wyłącznie cechą składnika (cecha własna), czy cechą składnika w kontekście przepisu (cecha kontekstowa).

  • Funkcja/właściwość Niektóre składniki przepisów charakteryzują się specyficznymi cechami czy właściwościami, które muszą zostać zachowane podczas zamiany. Przykładowo proszek do pieczenia pełni zazwyczaj funkcję środka spulchniającego, która musi zostać zachowana podczas zamiany. Ograniczenie twarde; cecha kontekstowa.
  • Kluczowe właściwości organoleptyczne Niektóre składniki wprowadzają konkretne właściwości organoleptyczne kluczowe z punktu widzenia niektórych przepisów. Przykładowo, w przepisie na stek z tuńczyka zastąpienie polędwicy z tuńczyka fasolą z puszki (bez dodatkowego procesu mającego na celu przerobienie fasoli) jest niedopuszczalne. Ograniczenie twarde; cecha kontekstowa.
  • Drugorzędne właściwości organoleptyczne Zamiana powinna w miarę możliwości zachowywać smak, zapach całego przepisu itp. Ograniczenie miękkie; cecha kontekstowa.
  • Dopuszczalność Proponowany składnik musi być akceptowalny dla konsumenta, np. zastąpienie schabu polędwicą wieprzową w diecie wegańskiej nie jest dopuszczalne. Ograniczenie twarde; cecha własna.
  • Preferencja dietetyczna Wszyscy różnimy się preferencjami smakowymi, wyborami dietetycznymi itp. Przykładowo, fleksitarianie preferują niespożywanie mięsa, ale mięso nie jest dla nich składnikiem niedopuszczalnym. Ograniczenie miękkie; cecha własna.
  • Brak współwystępowania Przypuszcza się, że produkty często występujące razem w przepisach nie są swoimi zastępnikami. Ograniczenie miękkie; cecha własna (ale wynikająca ze zbioru danych).
  • Współdzielony kontekst Przypuszcza się, że produkty występujące często razem z takimi samymi zbiorami składników mogą być swoimi zastępnikami. Ograniczenie miękkie; cecha własna (ale wynikająca ze zbioru danych).
  • Wartości odżywcze Sumaryczna wartość odżywcza przepisu powinna zostać zachowana. Ograniczenie miękkie; cecha własna (w ogólności cecha kontekstowa, ale w świetle przyjętych założeń o zamienianiu jednego składnika na raz staje się własna)
  • Dostępność Składniki róznią się dostępnością sezonową i geograficzną. Ograniczenie miękkie; cecha własna (ale zależna od miejsca i czasu wykorzystania).
  • Kategoria Przypuszcza się, że produkty z tej samej kategorii (np. mąki) są raczej lepszymi zastępnikami dla zadanego produktu niż produkty z zupełnie innej kategorii. Ograniczenie miękkie; cecha własna.
  • Nazwa W przypadku składników nowoczesnych nazwa może wprost wskazywać czego jest to zastępnik (np. wegański boczek jako zastępnik wędzonego boczku). Niestety, należy zwrócić uwagę, że w przypadku składników tradycyjnych nazwa może być myląca (np. mąka ziemniaczana nie koniecznie dobrym zastępnikiem mąki pszennej). Ograniczenie miękkie; cecha własna.

Z punktu widzenia miary istotne są wyłącznie ograniczenia miękkie, ponieważ składniki niespełniające ograniczeń twardych w ogóle nie powinny być rozważane jako możliwe zastępniki. Ponadto, ze względu na przyjęte założenia, na aktualnym etapie mogą zostać uwzględnione wyłącznie cechy własne produktów. Pozostawia to następujące cechy: Drugorzędne właściwości organoleptyczne, Preferencja dietetyczna, Brak współwystępowania, Współdzielony kontekst, Wartości odżywcze, Dostępność, Kategoria, Nazwa.

W przedstawionym rozwiązaniu wykorzystano wyłącznie następujące cechy: Preferencja dietetyczna, Wartości odżywcze, Kategoria. Pozostałe cechy zostały w bieżącej wersji pominięte z następujących powodów:

  • Drugorzędne właściwości organoleptyczne Planowano integrację z FlavorDB 12, [13], która póki co okazuje się niemożliwa ze względu na problemy z dostępnością usługi.
  • Brak współwystępowania, Współdzielony kontekst Na obecnym etapie zbiór danych TASTEset [14] nie jest powiazany z ontologią FoodOn 15, [16].
  • Dostępność Na wczesnym etapie projektu podjęto decyzję o całkowitym pominięciu tej cechy jako zbyt skomplikowanej do zamodelowania.
  • Nazwa Ontologia FoodOn nie obfituje w nowoczesne produkty, które zyskałyby w ten sposób. Z drugiej strony porównywanie nazw wymaga zwykle dość skomplikowanych miar, co mogłoby stać w sprzeczności z założeniem o wyjaśnialności miary.

Przedstawiona metoda tworzenia miar nie jest zamknięta na wprowadzanie nowych cech i kolejne wersje mogą wykorzystywać wymienione powyżej cechy.

UTA

Wprowadzenie do metody UTA

Jako bazę dla zaproponowanej metody tworzenia miar wykorzystano metodę wielokryterialnego wspomagania decyzji UTA [4]. Bardziej szczegółowe, a przystępnie napisane wprowadzenie do UTA można znaleźć w 5, poniżej natomiast przedstawiono podsumowanie najważniejszych aspektów. Ze względu na spodziewane grono odbiorców zapożycza się stosowane w uczeniu masznowym pojęcia, m.in., parametru jako wartości liczbowej dobieranej automatycznie w procesie optymalizacji oraz * hiperparametru* jako parametru konfiguracyjnego zwyczajowo ustawianego przez użytkownika. Należy podkreślić, że nie są to terminy zwyczajowo stosowane w kontekście metod wielokryterialnego wspomagania decyzji.

UTA zakłada, że istnieje pewien zbiór obiektów (wariantów) opisanych cechami liczbowymi. Każda z cech może być albo maksymalizowana albo minimalizowana (hiperparametr), znana jest też jej wartość najlepsza i najgorsza (hiperparamter). W UTA cechy transformowane są za pomocą niemalejących/nierosnących, nieujemnych funkcji odcinkami liniowych, tworząc tzw. cząstkowe funkcje użyteczności, przy czym liczba odcinków dla każdej z funkcji jest hiperparametrem, natomiast wartości współczynników kierunkowych i wyrazów wolnych są parametrami. Dla kryterium maksymalizowanego funkcja jest niemalejąca, natomiast dla kryterium minimalizowanego - nierosnąca.

Cząstkowe funkcje użyteczności są sumowane (po wszystkich cechach) do globalnej funkcji użyteczności U, przy czym wprowadza się dodatkowy czynnik regularyzacyjny wymagający, aby globalna funkcja użyteczności dla szutcznego obiektu składającego się wyłącznie z najgorszych wartości cech wynosiła 0, natomiast dla sztucznego obiektu składającego się wyłącznie z najlepszych wartości cech wynosiła 1.

Zakłada się ponadto, że pomiędzy niektórymi obiektami znana jest relacja preporządku, pełniąca rolę odpowiednika zbioru uczącego: dla dwóch obiektów a, b wiadomo albo, że a jest preferowany nad b, co powinno zostać odwzorowane przez globalną funkcję użyteczności jako U(a) > U(b), albo że są nierozróżnialne, co powinno zostać odwzorowane jako U(a) = U(b).

W odróżnieniu od metod uczenia maszynowego zamiast optymalizacji gradientowej stosuje się reprezentację jako problem matematycznego programowania liniowego i rozwiązuje przy wykorzystaniu tzw. solwerów. Należy zaznaczyć, że nie jest to reprezentacja w formie całkowitoliczbowego programowania liniowego i w związku z tym znalezienie rozwiązania odbywa się w czasie wielomianowym.

Wynikiem działania UTA jest globalna funkcja użyteczności U, która definiuje preporządek na wszystkich rozważanych wariantach: a jest preferowane nad b jeżeli U(a) > U(b) albo a jest nierozróżnialne z b jeżeli U(a) = U(b).

W kontekście rozważanego zagadnienia zastępowalności składników należy zwrócić uwagę, że za zdefiniowanie wartości hiperparametrów odpowiedzialny jest ekspert dziedzinowy, a nie użytkownik końcowy. Użytkownik końcowy korzysta (za pośrednictwem odpowiedniego interfejsu użytkownika) dopiero z gotowej globalnej funkcji użyteczności U.

Ponadto należy zwrócić uwagę, że ranking jest niezbędnym elementem odkrywania preferencji eksperta dziedzinowego. Bez rankingu można wyznaczyć tylko front Pareto, tzn. zbiór obiektów niezdominowanych przez żaden inny, natomiast nie można zbudować rankingu, ponieważ bez wiedzy o względnej ważności cech, o żadnej parze wariantów na froncie Pareto nie da się jednoznacznie powiedzieć, żeby jeden element był lepszy od drugiego. Dla przykładu rozważmy dwa obiekty: a oraz b oraz dwie maksymalizowane cechy. Niech a będzie miał wartości na tych cechach (0.2, 0.8), natomiast b odpowiednio (0.8, 0.2). Ponieważ cechy są maksymalizowane, więc b jest lepsze od a na pierwszej cesze, natomiast a jest lepsze od b na drugiej cesze. Bez dodatkowej wiedzy o względnej ważności cech (w UTA reprezentowanej przez parametry cząstkowych funkcji użyteczności) nie da się stwierdzić czy, z punktu widzenia eksperta dziedznowego, a jest lepsze od b, b jest lepsze od a czy może są nierozróżnialne.

Implementacja - klasa uta.RawUTA

Konsultacja z prof. Miłoszem Kadzińskim, specjalistą w dziedzinie wielokryterialnego wspomagania decyzji pracującym w Instytucie Informatyki Politechniki Poznańskiej, wykazała, że nie ma ogólnie przyjętej, powszechnie używanej biblioteki metod wspomagania decyzji w Pythonie. W związku z prostotą UTA podjęto decyzję o samodzielnej implementacji przy wykorzystaniu biblioteki cvxpy 6. Implementacja dostępna jest w klasie uta.RawUTA w pliku uta/rawuta.py. Konstruktor klasy RawUTA przyjmuje dwa argumenty:

  • features typu Sequence[Tuple[int, float, float]] - Sekwencja (np. lista) opisująca hiperparametry cech w formie trójek, składających się kolejno z: liczby odcinków liniowych, wartości najgorszej, wartości najlepszej.
  • same_tier_is_equivalent typu bool - Parametr konfiguracyjny wskazujący jak interpretować argumenty opisanej poniżej metody add.

Obiekt klasy RawUTA w ramach publicznego API oferuje trzy metody:

  • Dwuargumentową metodę add dodającą informacje o znanej relacji preporządku o następujących argumentach:

    • reference_ranking typu Sequence[Collection[Any]], stanowiące sekwencję kolekcji identyfikatorów obiektów. Obiekty z kolekcji reference_ranking[i] są preferowane nad obiektami z kolekcji reference_ranking[j] dla wszystkich j>i. Jeżeli same_tier_is_equivalent było ustawione na True, to obiekty w obrębie kolekcji reference_ranking[i] (dla każdego i) są uznawane za nierozróżnialne; w przeciwnym razie nie są dodawane żadne ograniczenia dotyczące par obiektów z tej samej kolekcji reference_ranking[i].
    • variants typu Mapping[Any, Sequence[float]] stanowiące odwzorowanie między identyfikatorami obiektów używanymi w reference_ranking, a wartościami cech w tym samym porządku, który był użyty w arugmencie features konstruktora.

    Metodę add można wywoływać wielokrotnie w celu dodania kolejnych informacji o znanej relacji preporządku, przy czym należy zaznaczyć, że add polega na globalnej unikalności identyfikatorów w reference_ranking, tzn. w przypadku odwołania do obiektu z tym samym identyfikatorem w kolejnych wywołaniach add oczekuje się, że wartości w variants przypisane temu identyfikatorowi będą identyczne, a dodawane relacje spójne między sobą.

  • Bezargumentową metodę solve, którą należy wywołać po wszystkich wywołaniach add w celu rozwiązania problemu programowania liniowego.

  • Jednoargumenowej metody U, której jedyny argument to sekwencja wartości cech opisujących obiekt, dla którego ma być obliczona wartość globalnej funkcji użyteczności U. Zwracany jest obiekt typu cvxpy.Expression, którego wartość liczbową można odczytać za pomocą pola value.

Testy jednostkowe oparte na 5, a zarazem przykłady użycia klasy uta.RawUTA znajdują się w pliku uta/test/test_rawuta.py.

Implementacja - klasa uta.UTA

Klasa uta.RawUTA ma stosunkowo niewygodny interfejs. W związku z tym wprowadzono klasę uta.UTA zdefiniowaną w pliku uta/uta.py oraz wykorzystywane przez nią klasy uta.FeatureSet oraz uta.FeatureDescriptor zdefiniowane w pliku uta/FeaturerSet.py. uta.FeatureDescriptor to dataclass, której rolą jest przechowywanie informacji o pojedynczej cesze: nazwie (pole name typu str), liczbie odcinków w funkcji odcinkami liniowej (pole n typu int), wartości najgorszej (pole worst typu float) oraz najlepszej (pole best typu float).

uta.FeatureSet to klasa abstrakcyjna, którą klasa uta.UTA wykorzystuje do pozyskiwania wartości cech. Głównym elementem klasy jest metoda compute, która przyjmuje jako jedyny argument identyfikator obiektu, a zwraca listę cech liczbowych typu List[float]. Ta metoda domyślnie rzuca wyjątek NotImplemented i musi zostać zaimplementowana w klasach pochodnych. uta.FeatureSet udostępnia tez jedno pole descriptors typu List[FeatureDescriptor], które klasa pochodna powinna wypełnić listą obiektów typu uta.FeatureDescriptor o identycznej długości co lista wartości zwracana przez compute. W końcu udostępniona jest metoda compute_batch która przyjmuje jako argument listę identyfikatorów, a zwraca listę list cech List[List[float]], domyślnie wywołując compute dla każdego identyfikatora i łącząc zwracane listy cech w jedną listę dwuwymiarową. Implementacje mogą przeciążyć compute_batch jeżeli mają możliwość bardziej efektywnego jednoczesnego obliczania cech dla wielu obiektów na raz, np. przez zapytanie SPARQL wykorzystujące słowo kluczowe VALUES.

Klasa uta.UTA ma API bardzo zbliżone do tego oferowanego przez uta.RawUTA z następującymi różnicami:

  • Argument features konstruktora jest typu List[FeatureSet], zostaje zapisany jako pole features.
  • Metoda add nie ma argumentu variants, który nie jest potrzebny, ponieważ obliczanie wartości cech jest odpowiedzialnością obiektów z pola features.
  • Metoda U przyjmuje identyfikator lub listę identyfikatorów obiektów, których cechy są obliczane za obiektów z pola features. Zwracana jest wartość liczbowa funkcji U jeżeli przekazano jeden identyfikator lub lista wartości liczbowych funkcji U jeżeli przekazano listę identyfikatorów.

Implementacja - klasa uta.RelativeUTA

Zaobserwowano, że założenie o istnieniu jednego, globalnego rankingu składników może nie być adekwatnym modelem dla miary zastępowalności składników. Wprowadzono w związku z tym pewną modyfikację API klasy uta.UTA oraz dodatkową, specjalizowaną implementację klasy uta.FeatureSet nazwaną uta.RelativeFeatureSet. Obie klasy są zaimplementowane w pliku uta/RelativeUTA.py.

uta.RelativeFeatureSet przyjmuje jako argument konstruktora obiekt klasy uta.FeatureSet oraz poza standardowym interfejsem uta.FeatureSet udostępnia pole reference, które domyślnie ma wartość None, a które musi zostać ustawione na identyfikator obiektu przed każdym wywołaniem metody compute lub compute_batch. uta.RelativeFeatureSet zamiast obliczać wartości cech w sposób bezwzględny (np. wartość energetyczna danego składnika wyrażona w kcal), oblicza jako cechy wartość bezwzględną różnic między cechami obiektu przekazanego jako argument do funkcji compute oraz obiektu, którego identyfikator jest w polu reference. Takie podejście umożliwia implementację opisanej we wstępie koncepcji zachowywania wartości odżywczej. Zakłada się, że brak różnicy jest zawsze najlepszą możliwą wartością.

uta.RelativeUTA jest owinięciem (ang. wrapper) klasy uta.UTA z następującymi różnicami:

  • Argument konstruktora features jest przekazywany bezpośrednio do konstruktora klasy uta.UTA, natomiast same_tier_is_equivalent jest zawsze ustawione na False.
  • Metoda add przyjmuje trzy argumenty: identyfikator obiektu referencyjnego reference, listę identyfikatorów obiektów lepszych od referencyjnego better oraz listę obiektów gorszych worse. reference jest ustawione jako wartość pola reference wszystkich obiektów klasy uta.RelativeFeatureSet na liście features, a pozostałe dwa argumenty są łączone jako dwuwymiarowa lista [better, worse] i przekazywane do metody uta.UTA.add.
  • Metoda U przyjmuje jako pierwszy argument reference identyfikator obiektu referencyjnego, który jest wykorzystywany tak samo jak w metodzie add. Drugi argument i wartość zwracana mają identyczną semantykę jak w uta.UTA.U.
  • Wprowadzona jest pomocnicza metoda recommend, która przyjmuje dwa argumenty: reference o semantyce j.w. oraz variants stanowiący kolekcję identyfikatorów. Zwracana jest para typu Tuple[Any, float], której pierwszy element to element kolekcji variants dla którego wartość funkcji U jest największa (przy ustalonym reference), a drugi argument to wartość funkcji U. Ta funkcja pełni funkcję rekomendera, który dla zadanego obiektu reference ma wybrać najlepszą alternatywę z kolekcji variants.

Testy jednostkowe i zarazem przykłady użycia znajdują się w pliku uta/test/test_RelativeUTA.py. Testy integracyjne wraz z mniej abstrakcyjnymi przykładami użycia znajdują się w plikach test_diabetes.py, test_glutenfree.py oraz test_vegan.py.

Reprezentacja wiedzy

Wykorzystane grafy wiedzy

Zakłada się, że każdy rozważany składnik jest identyfikowany za pomocą identyfikatorów (IRI) encji z grafu wiedzy. W bieżącej wersji przyjęto, że centralną częścią grafu wiedzy jest ontologia FoodOn i składniki są identyfikowane za pomocą IRI z jej przestrzeni nazw. Wczytywanie FoodOn zostało zaimplementowane w postaci metody foodon w pliku helpers.py, która nie przyjmuje argumentów, a zwraca obiekt klasy owlready2.Ontology biblioteki owlready2 3, [19] zawierający wczytaną ontologię. FoodOn oraz importowane przez nią ontologie są domyślnie pobierane z Internetu, natomiast dla zwiększenia efektywności wykorzystywany jest wbudowany w bibliotekę owlready2 mechanizm budowania pamięci podręcznej w katalogu cache/ontologies.

Dodatkowo z FoodOn powiązano WikiFCD 17, [18], graf wiedzy integrujący tabele wartości odżwyczych pochodzące z różnych źródeł do wspólnej reprezentacji. Mimo początkowych nadziei, że WikiFCD jest mocno zintegrowane z FoodOn okazało się, że tak nie jest i jednocześnie

  1. wiele składników w WikiFCD nie jest oznaczonych identyfikatorami z FoodOn;
  2. wiele składników z FoodOn występuje w WikiFCD, ale nie ma przypisanych żadnych informacji o wartościach odżywczych.

W pliku wikifcd2foodon.json znajdują się wszystkie powiązania między encjami WikiFCD oraz FoodOn, wygenerowane 29.06.2022 za pomocą następującego zapytania SPARQL zadanego do końcówki https://wikifcd.wiki.opencura.com/query/:

PREFIX p: <http://wikifcd.wiki.opencura.com/prop/>    
PREFIX ps: <http://wikifcd.wiki.opencura.com/prop/statement/> 
SELECT * WHERE {
    ?item p:P309/ps:P309 ?foodon.
}

Łącznie jest 1145 powiązań, podczas gdy w FoodOn samych podklas klasy food product FOODON_00001002 jest 13989 (patrz kod w załączniku I). Co więcej, jak wspomniano wcześniej, niektóre z istniejących powiązań są bezużyteczne do zbierania informacji o wartościach odżywczych. Przykładowo, encja sorghum kernel FOODON_03309978 jest odwzorowana w http://wikifcd.wiki.opencura.com/entity/Q569378. Niestety, WikiFCD nie oferuje żadnych informacji o wartościach odżywczych dla tej encji.

Żeby rozwiązać oba problemy zaproponowano tymczasowe rozwiązanie polegające na ręcznym odwzorowywaniu identyfikatorów FoodOn i WikiFCD w formie pliku tekstowego wikifcd2foodon.tsv. Podczas wczytywania pliku linie puste, linie składające się wyłącznie z białych znaków oraz linie, w których pierwszy nie-biały znak to # są ignorowane. Pozostałe linie dzielone są po białych znakach i uwzględniane są wyłącznie pierwsze dwa elementy wynikające z podziału. Oczekuje się, że pierwszy element będzie identyfikatorem z WikiFCD, albo w formie pełnego IRI, albo w formie wyłącznie części lokalnej (ang. local part, 1). W tej drugiej sytuacji jest uzupełniany o prefiks http://wikifcd.wiki.opencura.com/entity/ do utworzenia pełnego IRI. Analogicznie, dla drugiego elementu oczekuje się, że jest to albo pełne IRI encji z FoodOn, albo część lokalna, która zostaje uzupełniona prefiksem http://purl.obolibrary.org/obo/. Odwzorowania w wikifcd2foodon.tsv mają priorytet nad tymi zgromadzonymi w wikifcd2foodon.json, tzn. w razie odwzorowania encji z FoodOn w obu plikach uwzględniane jest odwzorowanie z wikifcd2foodon.tsv.

Integracja z WikiFCD została zaimplementowana w formie klasy WikiFCD w pliku WikiFCD.py. Wczytywanie odwzorowań z plików odbywa się w bezparametrowym konstruktorze klasy, natomiast pobieranie informacji z WikiFCD odbywa się za pomocą operatora [], którego jedynym argumentem jest łańcuch znaków (str) stanowiący pełne IRI encji z FoodOn. Zwracana wartość to albo None jeżeli nie znaleziono odwzorowania dla encji i w związku z tym nie można pobrać danych z WikiFCD, albo para typu Tuple[rdflib.URIRef, rdflib.Graph], gdzie pierwszy element pary to IRI z WikiFCD odczytany z odwzorowań wczytanych w konstruktorze, a przedstawiony jako obiekt klasy URIRef biblioteki rdflib 2, a drugi element to graf RDF zawierający fragment WikiFCD opisujący encję, której IRI zostało zwrócone jako pierwszy element pary.

Klasa WikiFCD nie operuje na zrzucie WikiFCD, zamiast tego komunikuje się bezpośrednio z kopią WikiFCD dostępną w Internecie. Dla zwiększenia efektywności klasa WikiFCD tworzy pamięć podręczną zawierającą pobrane fragmenty grafów, domyślnie znajdującą się w katalogu cache/wikifcd, który jest tworzony w konstruktorze. Nie zaimplementowano mechanizmu usuwania niepotrzebnych bądź nieaktualnych wpisów z pamięci podręcznej. Pamięć podręczna zorganizowana jest w formie nieskompresowanych plików w formacie Turtle (z rozszerzeniem ttl), o nazwach odpowiadających częściom lokalnym identyfikatorom z WikiFCD.

Transformacja do postaci wektora liczbowego

W celu przejścia z reprezentacji w formie grafu wiedzy do reprezentacji w formie wektorów liczbowych, wymaganych przez metodę UTA zaproponowano dwie klasy: OWLReadyClassMembershipFeatureSet zaimplementowaną w pliku OWLReadyClassMembershipFeatureSet.py oraz WikiFCDFeatureSet zaimplementowaną w pliku WikiFCDFeatureSet.py. Obie klasy implementują klasę abstrakcyjną uta.FeatureSet.

Konstruktor klasy OWLReadyClassMembershipFeatureSet oczekuje jako argumentów dwóch sekwencji zawierających obiekty biblioteki owlready2 reprezentujące nazwane klasy lub wyrażenia klasowe, oznaczone łącznie dalej jako ClassExpression: positive_classes oraz negative_classes. Każde z wyrażeń z obu sekwencji tworzy odrębną cechę, która przyjmuje wartości 0 lub 1. Dla wyrażeń z positive_classes 1 jest wartością najlepszą, podczas gdy dla negative_classes 0 jest wartością najlepszą. Niech classes reprezentuje sklejenie list positive_classes i negative_classes: classes = positive_classes + negative_classess. Metoda compute oczekuje jednego argumentu typu ClassExpression i zwraca wektor długości len(classes) taki, że i-ty element przyjmuje w nim wartość 1 jeżeli argument jest podklasą i-tego wyrażenia na liście classes i 0 w przeciwnym przypadku (tzn. gdy nie można wykazać, że jest podklasą).

Należy zwrócić uwagę, że owlready2 nie udostępnia efektywnego mechanizmu odpytywania o zachodzenie zawierania się wyrażeń klasowych. Tymczasowo zastosowano przybliżone rozwiązanie za pomocą bardzo ograniczonej implementacji indukcji strukturalnej zaimplementowanej w funkcji is_subclass w pliku helpers.py. Przedstawiona implementacja jest poprawna (ang. sound), ale nie kompletna (ang. complete) i docelowo powinna zostać zastąpiona rozwiązaniem, które posiada obie te cechy.

Klasa WikiFCDFeatureSet korzysta z opisanej wcześniej klasy WikiFCD do zbierania danych o wartościach odżywczych z WikiFDC. Graf zwrócony przez obiekt klasy WikiFDC jest odpytywany za pomocą zapytań SPARQL o cztery, zdefiniowane poniżej, wartości. W opisie wykorzystywana jest następująca konwencja: ?item to obiekt, dla którego jest odczytywana wartość; ?amount to odczytywana wartość; prefiks p: reprezentuje przestrzeń nazw http://wikifcd.wiki.opencura.com/prop/, psv: - http://wikifcd.wiki.opencura.com/prop/statement/value/ , wikibase: - http://wikiba.se/ontology#, a wb: - http://wikifcd.wiki.opencura.com/entity/.

  • Energia wyrażona w kilokaloriach za pomocą wzorca ?item p:P6/psv:P6 [wikibase:quantityAmount ?amount; wikibase:quantityUnit wb:Q11 ]
  • Białko w gramach za pomocą wzorca ?item p:P7/psv:P7 [wikibase:quantityAmount ?amount; wikibase:quantityUnit wb:Q8 ]
  • Tłuszcz w gramach za pomocą wzorca ?item p:P8/psv:P8 [wikibase:quantityAmount ?amount; wikibase:quantityUnit wb:Q8 ]
  • Sód w miligramach za pomocą wzorca ?item p:P18/psv:P18 [wikibase:quantityAmount ?amount; wikibase:quantityUnit wb:Q15 ]

Reprezentacja wszystkich cech jest ustawiona jako składająca się z jednego odcinka liniowego. Białko jest ustawione jako cecha maksymalizowana, natomiast pozostałe cechy jako minimalizowane. Metoda compute oczekuje identyfikatora IRI z onotologi FoodOn w formie łańcucha znaków str albo obiektu, którego atrybut iri będzie takim identyfikatorem, a zwraca listę składającą się z czterech liczb zmiennoprzecinkowych odpowiadających opisanym powyżej cechom.

Przykłady użycia obu klas zawarte są w testach integracyjnych w plikach test_diabetes.py, test_glutenfree.py oraz test_vegan.py.

Wykorzystanie danych z serwisu Food Data Central

Na dzień 12.07.2022 ostatni udany dostęp do Internetowej kopii WikiFCD był 04.07.2022, od tego czasu zwracany jest kod błędu HTTP 503 Service Temporarily Unavailable. W związku z tym opracowano alternatywny sposób zbierania informacji o składnikach odżywczych korzystający z baz danych udostępnianych przez U.S. Department of Agriculture w serwisie Food Data Central (FDC): Foundation Foods oraz Global Branded Foods w wersjach z kwietnia 2022 20.

Wczytywanie danych z plików w formacie JSON zostało zaimplementowane w formie klasy FDC w pliku FDC.py o bezparametrowym konstruktorze oraz operatorze [], który oczekuje jako jedynego argumentu łańcucha znaków (str) stanowiącego pełne IRI encji z FoodOn, bądź obiektu, którego atrybut iri będzie takim łańcuchem znaków. Operator [] zwraca listę słowników, które zawierają dane z FDC. Klasa FDC jest w stanie samodzielnie pobrać niezbędne dane z serwisu FDC oraz, dla zwiększenia efektywności, zapisać ich kopie w pamięci podręcznej w katalogu cache/FDC.

Odwzorowanie z IRI na wewnętrzne identyfikatory baz FDC odbywa się za pomocą dwóch plików tekstowych, w których każda linia stanowi pojedyncze odwzorowanie i składa się kolejno z następujących pól rozdzielonych białymi znakami: identyfikator FDC ID, IRI encji lub jego lokalna części oraz opcjonalny, ignorowany komentarz (do końca linii). Przy wczytywaniu plików puste linie, linie składające się wyłącznie z białych znaków oraz linie, w których pierwszy nie-biały znak to # są ignorowane, a części lokalne są uzupełniane do pełnych IRI przez dodanie prefiksu http://purl.obolibrary.org/obo/. Obsługiwane jest odwzorowanie jednego IRI na wiele FDC ID, w takim przypadku operator [] zwraca listę wszystkich odwozorowanych produktów. Odwzorowania zapisane w pliku fdc2foodon.tsv są odwzorowaniami stworzonymi ręcznie, natomiast te w pliku fdc2foodon-auto.tsv zostały stworzone automatycznie przy wykorzystaniu funkcji generate_mappings zaimplementowanej w pliku FDC.py. Automatyczne generowanie odwzorowań polegało na połączeniu ze sobą encji FoodOn oraz produktów z bazy FDC dla których zbiór (bez powtórzeń) słów w etykiecie encji oraz w polu description produktu były identyczne z dokładnością do kolejności słów i wielkości liter. Wyrywkowa ręczna analiza wskazała, że nie jest to idealna metoda, np. flour tortilla zostało odwzorowane w tortilla flour.

Ponieważ wczytywanie całych baz FDC zajmuje dużo czas, zastosowano następujące optymalizacje:

  • Wszystkie instancje klasy FDC współdzielą wczytane dane, a samo wczytywanie danych odbywa się przy pierwszym wywołaniu konstruktora.
  • Wszystkie produkty wymienione w plikach z odwzorowaniami są zapisywane w pamięci podręcznej, w pliku cache/FDC/mapped.json.gz. Ten plik jest uznawany za nieaktualny i generowany na nowo, jeżeli którykolwiek z plików z odwzorowaniami (fdc2foodon.tsv , fdc2foodon-auto.tsv) ma świeższą datę modyfikacji niż plik z pamięci podręcznej.

Na bazie klasy FDC zaimplementowano w pliku FDC.py klasę FDCFeatureSet, która z punktu widzenia API oraz zwracanych cech stanowi bezpośredni zastępnik dla klasy WikiFCDFeatureSet. Ze względu na możliwośc odwzorowania jednej encji w wiele produktów z FDC zastosowano uśrednianie, tzn. jako wartość danej cechy dla encji przyjmowana jest średnia wartość danej cechy po wszystkich odzwzorowanych produktach. W związku z awarią WikiFDC zastąpiono w testach integracyjnych odwołania do klasy WikiFCDFeatureSet odwołaniami do klasy FDCFeatureSet bez pogorszenia wyników testów.

Przypadki użycia

Cukrzyca

Założono, że w diecie cukrzycowej preferowane powinny być produkty o niskim indeksie glikemicznym (IG). Ani w FoodOn, ani w WikiFCD indeks glikemiczny nie jest dostępny, stanowi on zatem złoty standard, z którego nie można bezpośrednio skorzystać w obliczeniach, ale który można wykorzystać do oceny. W ramach testu przedstawionego w klasie Diabetes zaimplementowanej w pliku test_diabetes.py wykorzystano uta.RelativeUTA oparte na cechach generowanych przez WikiFCDFeatureSet oraz na ich wartościach zrelatywizowanych za pomocą RelativeFeatureSet. Jako złoty standard wykorzystano informacje pochodzące z 7. W ramach zbioru uczącego ( znanego preporządku) wykorzystano trzy mąki, przedstawione w kolejności od najlepszej do najgorszej: soybean flour obo.FOODON_03302142 (niski IG), rye flour obo.FOODON_03302492 (średni IG), white rice flour obo.FOODON_03307541 (wysoki IG). Jako zbiór kandydatów, z którego należało dokonać wyboru i jednocześnie zbiór obiektów, które były zastępowane, wykorzystano następujące rodzaje mąki: tapioca flour obo.FOODON_03310681 (wysoki IG), brown rice flour obo.FOODON_00003351 (średni IG), potato starch obo.FOODON_03307543 (wysoki IG), chickpea flour obo.FOODON_03304537 (niski IG). Obliczona miara we wszystkich przypadkach prawidłowo wskazała (przy użyciu metody uta.RelativeUTA.recommend) chickpea flour obo.FOODON_03304537 jako najlepszy zastępnik dla wszystkich czterech rodzajów mąki, natomiast po usunięciu chickpea flour ze zbioru - brown rice flour obo.FOODON_00003351 jako zastępnik dla wszystkich trzech pozostałych rodzajów mąki.

Dieta bezglutenowa

Na podstawie 8 przyjęto, że w diecie bezglutenowej należy unikać pszenicy, jęczmienia, żyta oraz owsa. Opisany przypadek użycia został zaimplementowany w klasie GlutenFree w pliku test_glutenfree.py. Wykorzystano uta.RelativeUTA oraz trzy sposoby konstruowania cech:

  • Przynależność do wyrażenia klasowego wheat food product OR barley food product OR oat food product OR rye food product OR triticale food product FOODON_00001141 | FOODON_00001191 | FOODON_00001189 | FOODON_00001190 | FOODON_00002552 jako cecha minimalizowana obliczana za pomocą OWLReadyClassMembershipFeatureSet
  • Przynależność do wyrażenia klasowego gravy or sauce FOODON_00001931 jako cecha względna obliczana za pomocą klas RelativeFeatureSet oraz OWLReadyClassMembershipFeatureSet
  • Różnice w wartościach odżywczych obliczane za pomocą RelativeFeatureSet(WikiFCDFeatureSet())

Jako zbiór uczący przedstawiono dwa rankingi oparte o 9:

  • Ranking I
    1. buckwheat noodle FOODON_03309979, shirataki noodle FOODON_03311767
    2. pasta FOODON_03306347
    3. apple (whole, raw) FOODON_03301710
  • Ranking II
    1. sorghum seed (whole) FOODON_00003751, rice (polished) FOODON_03304560
    2. barley (pearled) FOODON_03306062
    3. apple (whole, raw) FOODON_03301710

Jako zbiór kandydatów przyjęto następujące encje: red kidney bean (canned) FOODON_03303520, apple (whole, raw) FOODON_03301710, canola oil FOODON_03302578, wheat gluten FOODON_03310809, lard FOODON_03302051, white rice flour FOODON_03307541, whole wheat flour FOODON_03302340, tamari sauce FOODON_03309556. Testy potwierdzają, że obliczona dla podanej listy kandydatów prawidłowo wskazuje white rice flour jako bezglutenowy odpowiednik whole wheat flour oraz tamari sauce jako bezglutenowy odpowiednik zarówno dla tamari sauce jak i dla soy sauce FOODON_03301115.

W nawiązaniu do dyskusji we wstępie należy podkreślić, że jeżeli mowa o diecie faktycznie bezglutenowej, a nie niskoglutenowej, to zbiór potencjalnych zastępników musi być wstępnie przefiltrowany tak, żeby wybór najlepszego zastępnika dokonywany był wyłącznie spośród produktów niezawierających glutenu. Należy również zaznaczyć, że FoodOn wydaje się nie być dobrym źródłem wiedzy w tym zakresie, przykładowo sos sojowy wytwarzany jest przy udziale zarówno soi, jak i pszenicy, co jednak nie wynika z opisu encji soy sauce FOODON_03301115.

Dieta wegetariańska

W klasie Vegan zaimplementowanej w pliku test_vegan.py opracowano przypadek wyboru subsytutu w diecie wegańskiej. Wykorzystano uta.RelativeUTA oraz dwa zbiory cech:

  • Przynależność do klas obliczana za pomocą OWLReadyClassMembershipFeatureSet, gdzie zbiór klas pozytywnych składał się z jednego wyrażenia klasowego algal food product OR fungus food product OR microbial food product OR plant food product OR plant based refined or partially-refined food product OR plant based meat product analog FOODON_00001184 | FOODON_00001143 | FOODON_00001145 | FOODON_00001015 | FOODON_00002131 | FOODON_00002129 natomiast zbiór klas negatywnych z dwóch wyrażeń: vertebrate animal food product OR seafood product OR invertebrate food product FOODON_00001092 | FOODON_00001046 | FOODON_00001176 oraz spice or herb FOODON_00001242
  • Różnice w wartościach odżywczych obliczane za pomocą RelativeFeatureSet(WikiFCDFeatureSet())

Jako zbiór uczący wykorzystano dwa rankingi:

  • Opracowany na podstawie 10:
    1. imitation bacon bit FOODON_03305199
    2. bacon (smoked) FOODON_03309992
    3. apple (whole, raw) FOODON_03301710
  • Opracowany na podstawie 11:
    1. tempeh FOODON_03304999, tofu food product FOODON_03309664, vegetable protein ( textured) FOODON_03311469
    2. beef (raw) FOODON_03309737, turkey (raw, ground) FOODON_03311109
    3. thyme (dried) FOODON_03301215, vanilla bean (whole) FOODON_00003738

Rozważano zbiór składający się z pięciu możliwych zastępników: red kidney bean (canned) FOODON_03303520, apple ( whole, raw) FOODON_03301710, canola oil FOODON_03302578, wheat gluten FOODON_03310809, lard FOODON_03302051. W ramach testów wykazano, że zarówno beef (raw) FOODON_03309737 jak i pork (fresh) FOODON_03317271 są prawidłowo zamieniane na red kidney bean (canned); tallow ( edible) FOODON_03315521 na canola oil (zamiast na lard), a honey UBERON_0036016 na apple (whole, raw).

Bibliografia

Jeżeli poniższa bibliografia wydaje się niekompletna to znaczy, że pozycje, które składają się wyłącznie z odnośników do stron Internetowych zostały zintegrowane jako odnośniki bezpośrednio w tekście. Pełna treść bibliografii znajduje się w pliku README.md.

[4]: Jacquet-Lagréze, E. and J. Siskos, “Assessing a Set of Additive Utility Functions for Multicriteria Decision Making: The UTA Method,” Eur J of Oper Res, 10(2), 1982, 151-164.

[13]: Garg N, Sethupathy A, Tuwani R, Nk R, Dokania S, Iyer A, Gupta A, Agrawal S, Singh N, Shukla S, Kathuria K, Badhwar R, Kanji R, Jain A, Kaur A, Nagpal R, Bagler G. FlavorDB: a database of flavor molecules. Nucleic Acids Res. 2018 Jan 4;46(D1):D1210-D1216. doi: 10.1093/nar/gkx957. PMID: 29059383; PMCID: PMC5753196.

[14]: Anna Wróblewska, Agnieszka Kaliska, Maciej Pawlowski, Dawid Wisniewski, Witold Sosnowski, Agnieszka Lawrynowicz: TASTEset - Recipe Dataset and Food Entities Recognition Benchmark. CoRR abs/2204.07775 (2022) https://arxiv.org/abs/2204.07775

[16]: Dooley, D.M., Griffiths, E.J., Gosal, G.S. et al. FoodOn: a harmonized food ontology to increase global food traceability, quality control and data integration. npj Sci Food 2, 23 (2018). https://doi.org/10.1038/s41538-018-0032-6

[18]: Katherine Thornton, Kenneth Seals-Nutt, Mika Matsuzaki: Introducing WikiFCD: Many Food Composition Tables in a Single Knowledge Base. JOWO 2021

[19]: Lamy JB. Owlready: Ontology-oriented programming in Python with automatic classification and high level constructs for biomedical ontologies. Artificial Intelligence In Medicine 2017;80:11-28

Załącznik I: Zliczanie podklas klasy FOODON_00001002

from helpers import foodon

queue = [foodon().search_one(iri="http://purl.obolibrary.org/obo/FOODON_00001002")]
visited = set()
while len(queue) > 0:
    e = queue.pop(0)
    if e not in visited:
        visited.add(e)
        queue += e.descendants()
print("Visited", len(visited))

similarity's People

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.