Implemented neural network prediction for polygenic diseases to replace old method. Added autism and homosexualness to genetic analyses.

This commit is contained in:
Simon Sarasova 2024-08-13 13:25:47 +00:00
parent 1f30bfa71c
commit 8bc2bc01f3
No known key found for this signature in database
GPG key ID: EEDA4103C9C36944
50 changed files with 2716 additions and 3913 deletions

View file

@ -6,6 +6,7 @@ Small and insignificant changes may not be included in this log.
## Unversioned Changes
* Implemented neural network prediction for polygenic diseases to replace old method. Added autism and homosexualness to genetic analyses. - *Simon Sarasova*
* Increased the quantity of attributes that are extracted from the OpenSNP biobank data archive. - *Simon Sarasova*
* Added numeric traits to genetic analyses. - *Simon Sarasova*
* Improved Documentation.md and Future-Plans.md. - *Simon Sarasova*

View file

@ -9,4 +9,4 @@ Many other people have written code for modules which are imported by Seekia. Th
Name | Date Of First Commit | Number Of Commits
--- | --- | ---
Simon Sarasova | June 13, 2023 | 277
Simon Sarasova | June 13, 2023 | 278

View file

@ -289,9 +289,9 @@ There could be several analysis methods. These analysis methods will serve as an
Providing an open source ancestral analysis method is essential for race aware mate discovery technology to be credibly neutral. There already exist multiple open source ancestral analysis packages.
### Add Custom Type Illnesses
### Add Complex Disease Diagnosis
Many genetic illnesses are not able to be detected using the methods implemented in the `monogenicDiseases` or the `polygenicDiseases` packages.
Many genetic diseases are not able to be detected using the methods implemented in the `monogenicDiseases` or the `polygenicDiseases` packages.
Examples include diseases such as Fragile X and Turner's Syndrome.
@ -299,11 +299,7 @@ A new format called `complexDiseases` could be created.
Each disease can have a function that takes in a genome map and returns a diagnosis.
Many of these diseases may require additional data from the raw genome files that is not included in the genome map.
The `ReadRawGenomeFile` function should be able to read this relevant data.
The GUI would also have an accompanying set of pages to display these Custom illnesses.
The GUI would also have an accompanying set of pages to display complex diseases.
### Add Polygenic Disease Probability Risk
@ -313,23 +309,17 @@ Meaning, we want to tell the user the estimated probability that they will get a
Example: Normal risk = 5%, Your risk = 10%
We should be able to calculate this risk. We know the polygenic disease odds ratio of a base pair `(odds of disease with base pair)/(odds of disease with standard (common) base pair)`. We know the average probability of disease for the general population for each age period. We know the probability of each base pair for the general population.
This will be the most useful statistic for users trying to understand their polygenic disease risk.
Knowing that the probability of a particular type of cancer has increased by 10x is very different depending on the probability of getting the cancer.
Knowing that your risk score for a particular type of cancer is 10/10 is much less useful than understanding your probability of getting the cancer.
If the general population probability of getting cancer X is 5%, and the user's adjusted risk is 50%, that is a significant increase. However, if the general population risk is 0.1%, and the user's adjusted risk is 1%, then the user does not need to change their behavior or worry much.
### Add Neural Network Genetic Predictions
### Get Genetic Training Data
The current method for predicting polygenic disease risks and traits is not as informative and accurate as using neural nets.
We use neural networks to predict traits and polygenic diseases. We have to train these networks using example training data. This training data is a collection of people's genomes and the trait/polygenic disease information for each person.
Our current model adds and subtracts the likelihood values of various SNPs that are reported to have an effect on polygenic diseases and traits.
A much better method is to train a neural net to predict traits and polygenic diseases on a large number of genes. There are methods that exist to find the set of genes that have an effect on each trait/disease. For example, height is said to be effected by ~10,000 SNPs. Many GWAS studies exist which report which genes are responsible for certain traits and diseases. These are the genes to feed into the neural net for each trait/disease. These are also the genes that users will share in their profiles. I have already started to try to build this system. See `geneticPrediction.go` for an implementation of trait prediction using neural networks, and `createCoupleGeneticAnalysis.go` for information on how offspring predictions would work.
This method requires training data, which is largely unavailable for public use. We need fully open training data, not data that requires registration or permission to download.
Good training data is largely unavailable for public use. We need fully open training data, not data that requires registration or permission to download.
[OpenSNP.org](https://opensnp.org) is a free genomic data repository. OpenSNP relies on user submitted data, which can be falsified. OpenSNP should add a verification system so data provided by trustworthy people can be prioritized.
@ -339,10 +329,10 @@ Whoever collects the data needs to choose what data to collect from each person.
Some examples of data to collect:
* Collecting polygenic disease information would enable prediction of polygenic disease risk.
* Collecting polygenic disease information enables prediction of polygenic disease risk.
* Pictures and scans of participants faces would enable a genetic test for facial structure
* Personality tests would enable prediction of personality
* Measuring height would enable prediction of height
* Measuring height enables prediction of height
These kinds of genetic tests would allow parents to choose what their offspring will look like, their personality, and their intelligence.
@ -356,10 +346,12 @@ All of this is already possible, but will become easier with the proliferation o
### Add more diseases and traits
This task entails entering disease/trait SNP data from SNPedia.com and other sources. The bases have to be flipped if the orientation on SNPedia is minus. This requires flipping G/C and A/T. At least 3 people should check any added disease SNPs to ensure accuracy.
Adding monogenic diseases entails entering disease SNP data from SNPedia.com and other sources. The bases have to be flipped if the orientation on SNPedia is minus. This requires flipping G/C and A/T. At least 3 people should check any added disease SNPs to ensure accuracy.
This is a tedious data entry process with negative consequences if mistakes are made. Many users could falsely believe they have monogenic diseases, which could trigger mental health crises.
Adding polygenic diseases/traits requires training data and access to genome wide association studies. Seekia should also have the ability to perform genome wide association studies to find causal genes for traits.
### Interactive Map
Seekia should have an interactive world map. It would be similar to OpenStreetMaps, but with much less detail. It would only need to contain borders of countries and states as lines. It would be able to display latitude/longitude coordinates on the map as points.

View file

@ -569,7 +569,7 @@ func setPolygenicDiseaseLociExplainerPage(window fyne.Window, previousPage func(
description1 := getLabelCentered("Each polygenic disease has a set of associated genome loci.")
description2 := getLabelCentered("These are locations on the genome that can be tested to determine disease risk.")
description3 := getLabelCentered("The more loci that your genome contains, the more accurate your disease risk score will be.")
description3 := getLabelCentered("The more loci that your genome sequence contains, the more accurate your disease risk score will be.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3)
@ -615,65 +615,6 @@ func setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window fyne.Win
}
func setPolygenicDiseaseLocusRiskWeightExplainerPage(window fyne.Window, previousPage func()){
title := getPageTitleCentered("Help - Locus Risk Weight")
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Locus Risk Weight")
description1 := getLabelCentered("A polygenic disease risk score is calculated by testing many locations on a genome.")
description2 := getLabelCentered("A genome will have a risk weight for each locus.")
description3 := getLabelCentered("A negative weight reduces the risk of the disease.")
description4 := getLabelCentered("A positive weight increases the risk of the disease.")
description5 := getLabelCentered("A 0 weight has no effect on the risk.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5)
setPageContent(page, window)
}
func setOffspringPolygenicDiseaseLocusRiskWeightExplainerPage(window fyne.Window, previousPage func()){
title := getPageTitleCentered("Help - Locus Risk Weight")
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Offspring Locus Risk Weight")
description1 := getLabelCentered("A polygenic disease risk score is calculated by testing many locations on a genome.")
description2 := getLabelCentered("A genome will have a risk weight for each locus.")
description3 := getLabelCentered("A negative weight reduces the risk of the disease.")
description4 := getLabelCentered("A positive weight increases the risk of the disease.")
description5 := getLabelCentered("A 0 weight has no effect on the risk.")
description6 := getLabelCentered("An offspring's locus risk weight represents the average risk weight for all 4 possible locus outcomes.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6)
setPageContent(page, window)
}
func setPolygenicDiseaseLocusRiskWeightProbabilityExplainerPage(window fyne.Window, previousPage func()){
title := getPageTitleCentered("Help - Risk Weight Probability")
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Locus Risk Weight Probability")
description1 := getLabelCentered("A polygenic disease risk score is calculated by testing many locations on a genome.")
description2 := getLabelCentered("A genome will have a risk weight for each locus.")
description3 := getLabelCentered("A risk weight probability describes the probability of having that risk weight.")
description4 := getLabelCentered("For example, lets suppose a risk weight of 2 has a probability of 5%")
description5 := getLabelCentered("This means that 5% of people will have a risk weight of 2 at this locus.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5)
setPageContent(page, window)
}
func setDiscreteTraitNeuralNetworkPredictionExplainerPage(window fyne.Window, previousPage func()){
title := getPageTitleCentered("Help - Neural Network Prediction")
@ -768,7 +709,7 @@ func setDiscreteTraitRulesExplainerPage(window fyne.Window, previousPage func())
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Trait Rules")
subtitle := getPageSubtitleCentered("Discrete Trait Rules")
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
description2 := getLabelCentered("Discrete traits has multiple outcomes, and each outcome has an associated score.")

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
package gui
// viewGeneticReferencesGui.go implements pages to display information about genetic diseases and traits
@ -245,217 +244,6 @@ func setViewPolygenicDiseaseDetailsPage(window fyne.Window, diseaseName string,
}
func setViewPolygenicDiseaseLocusDetailsPage(window fyne.Window, diseaseName string, locusIdentifier string, previousPage func()){
currentPage := func(){setViewPolygenicDiseaseLocusDetailsPage(window, diseaseName, locusIdentifier, previousPage)}
title := getPageTitleCentered("Viewing Locus Details")
backButton := getBackButtonCentered(previousPage)
locusObject, err := polygenicDiseases.GetPolygenicDiseaseLocusObject(diseaseName, locusIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
locusRSID := locusObject.LocusRSID
locusReferencesMap := locusObject.References
locusRSIDsList := []int64{locusRSID}
// We add aliases to locusRSIDsList
anyAliasesExist, rsidAliasesList, err := locusMetadata.GetRSIDAliases(locusRSID)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (anyAliasesExist == true){
locusRSIDsList = append(locusRSIDsList, rsidAliasesList...)
}
metadataExists, locusMetadataObject, err := locusMetadata.GetLocusMetadata(locusRSID)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (metadataExists == false){
setErrorEncounteredPage(window, errors.New("setViewPolygenicDiseaseLocusDetailsPage called with locusRSID missing from locusMetadata."), previousPage)
return
}
diseaseNameLabel := widget.NewLabel("Disease Name:")
diseaseNameText := getBoldLabel(diseaseName)
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, layout.NewSpacer())
getLocusNamesLabelText := func()string{
if(len(locusRSIDsList) == 1){
return "Locus Name:"
}
return "Locus Names:"
}
locusNamesLabelText := getLocusNamesLabelText()
locusRSIDStringsList := make([]string, 0, len(locusRSIDsList))
for _, locusRSID := range locusRSIDsList{
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
locusRSIDName := "rs" + locusRSIDString
locusRSIDStringsList = append(locusRSIDStringsList, locusRSIDName)
}
locusNamesListString := strings.Join(locusRSIDStringsList, ", ")
locusNamesLabel := widget.NewLabel(locusNamesLabelText)
locusNamesText := getBoldLabel(locusNamesListString)
locusNamesRow := container.NewHBox(layout.NewSpacer(), locusNamesLabel, locusNamesText, layout.NewSpacer())
getLocusGeneNameLabelValue := func()string{
locusGeneInfoIsKnown := locusMetadataObject.GeneInfoIsKnown
if (locusGeneInfoIsKnown == false){
return "Unknown"
}
locusGeneExists := locusMetadataObject.GeneExists
if (locusGeneExists == false){
return "None"
}
locusGeneName := locusMetadataObject.GeneNamesList[0]
return locusGeneName
}
locusGeneNameLabelValue := getLocusGeneNameLabelValue()
geneNameLabel := widget.NewLabel("Gene Name:")
geneNameText := getBoldLabel(locusGeneNameLabelValue)
geneNameRow := container.NewHBox(layout.NewSpacer(), geneNameLabel, geneNameText, layout.NewSpacer())
viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
setViewGeneticAnalysisReferencesPage(window, "Locus", locusReferencesMap, currentPage)
}))
getBasePairsGrid := func()(*fyne.Container, error){
locusRiskWeightsMap := locusObject.RiskWeightsMap
locusBasePairProbabilitiesMap := locusObject.BasePairProbabilitiesMap
riskWeightLabel := getItalicLabelCentered("Risk Weight")
probabilityLabel := getItalicLabelCentered("Probability Of Weight")
riskWeightColumn := container.NewVBox(riskWeightLabel, widget.NewSeparator())
riskWeightProbabilityColumn := container.NewVBox(probabilityLabel, widget.NewSeparator())
// We create a new map with duplicates removed
locusBasePairProbabilitiesMap_DuplicatesRemoved := make(map[string]float64)
for basePair, basePairProbability := range locusBasePairProbabilitiesMap{
baseA, baseB, semicolonFound := strings.Cut(basePair, ";")
if (semicolonFound == false) {
return nil, errors.New("Invalid base pair found in locusBasePairProbabilitiesMap: " + basePair)
}
basePairDuplicate := baseB + ";" + baseA
existingProbabilityValue, exists := locusBasePairProbabilitiesMap_DuplicatesRemoved[basePairDuplicate]
if (exists == true){
// The duplicate has already been added.
// We make sure the probability values match
if (existingProbabilityValue != basePairProbability){
return nil, errors.New("locusBasePairProbabilitiesMap contains duplicate base pair with different value")
}
continue
}
locusBasePairProbabilitiesMap_DuplicatesRemoved[basePair] = basePairProbability
}
// All probabilities are mutually exclusive (you can only have 1 base pair for each genome locus)
// Thus, we can add them together to get a total probability for each risk weight
// Map structure: Risk Weight -> Probability of having weight
riskWeightProbabilitiesMap := make(map[int]float64)
for basePair, basePairProbability := range locusBasePairProbabilitiesMap_DuplicatesRemoved{
getBasePairRiskWeight := func()int{
basePairRiskWeight, exists := locusRiskWeightsMap[basePair]
if (exists == false){
// This base pair has no known weight. We treat it as a 0 weight.
return 0
}
return basePairRiskWeight
}
basePairRiskWeight := getBasePairRiskWeight()
riskWeightProbabilitiesMap[basePairRiskWeight] += basePairProbability
}
// Now we sort risk weights in order of least to greatest
allRiskWeightsList := helpers.GetListOfMapKeys(riskWeightProbabilitiesMap)
slices.Sort(allRiskWeightsList)
for _, riskWeight := range allRiskWeightsList{
riskWeightProbability, exists := riskWeightProbabilitiesMap[riskWeight]
if (exists == false){
return nil, errors.New("Risk weight probability not found in riskWeightProbabilitiesMap")
}
riskWeightString := helpers.ConvertIntToString(riskWeight)
riskWeightPercentageProbability := riskWeightProbability * 100
riskWeightProbabilityString := helpers.ConvertFloat64ToStringRounded(riskWeightPercentageProbability, 2)
riskWeightProbabilityFormatted := "~" + riskWeightProbabilityString + "%"
riskWeightText := getBoldLabelCentered(riskWeightString)
riskWeightProbabilityText := getBoldLabelCentered(riskWeightProbabilityFormatted)
riskWeightColumn.Add(riskWeightText)
riskWeightProbabilityColumn.Add(riskWeightProbabilityText)
riskWeightColumn.Add(widget.NewSeparator())
riskWeightProbabilityColumn.Add(widget.NewSeparator())
}
riskWeightHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setPolygenicDiseaseLocusRiskWeightExplainerPage(window, currentPage)
})
riskWeightColumn.Add(riskWeightHelpButton)
probabilityHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setPolygenicDiseaseLocusRiskWeightProbabilityExplainerPage(window, currentPage)
})
riskWeightProbabilityColumn.Add(probabilityHelpButton)
basePairsGrid := container.NewHBox(layout.NewSpacer(), riskWeightColumn, riskWeightProbabilityColumn, layout.NewSpacer())
return basePairsGrid, nil
}
basePairsGrid, err := getBasePairsGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), locusNamesRow, widget.NewSeparator(), geneNameRow, widget.NewSeparator(), viewReferencesButton, widget.NewSeparator(), basePairsGrid)
setPageContent(page, window)
}
func setViewGeneticAnalysisReferencesPage(window fyne.Window, referencesTopic string, referencesMap map[string]string, previousPage func()){
currentPage := func(){setViewGeneticAnalysisReferencesPage(window, referencesTopic, referencesMap, previousPage)}
@ -644,5 +432,3 @@ func setViewDiscreteTraitRuleDetailsPage(window fyne.Window, traitName string, r

File diff suppressed because it is too large Load diff

View file

@ -945,9 +945,7 @@ func GetFakeProfile(profileType string, identityPublicKey [32]byte, identityPriv
diseaseLociList := diseaseObject.LociList
for _, locusObject := range diseaseLociList{
locusRSID := locusObject.LocusRSID
for _, locusRSID := range diseaseLociList{
shareableRSIDsMap[locusRSID] = struct{}{}
}

View file

@ -27,7 +27,6 @@ import "seekia/internal/helpers"
import "errors"
import mathRand "math/rand/v2"
import "slices"
import "maps"
import "reflect"
@ -512,7 +511,6 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
for _, diseaseObject := range polygenicDiseaseObjectsList{
diseaseName := diseaseObject.DiseaseName
diseaseLociList := diseaseObject.LociList
// This map stores the polygenic disease info for each genome pair
// Map Structure: Genome Pair Identifier -> OffspringGenomePairPolygenicDiseaseInfo
@ -532,9 +530,13 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
return errors.New("addGenomePairDiseaseInfoToDiseaseMap called with unknown person2GenomeIdentifier.")
}
anyOffspringLocusTested, genomePairOffspringAverageRiskScore, quantityOfLociTested, genomePairOffspringDiseaseLociInfoMap, genomePairSampleOffspringRiskScoresList, err := GetOffspringPolygenicDiseaseInfo(diseaseLociList, person1LocusValuesMap, person2LocusValuesMap)
neuralNetworkExists, anyOffspringLocusKnown, offspringAverageRiskScore, accuracyRangesMap, predictedRiskScoresList, quantityOfLociKnown, quantityOfParentalPhasedLoci, err := GetOffspringPolygenicDiseaseAnalysis(diseaseObject, person1LocusValuesMap, person2LocusValuesMap)
if (err != nil) { return err }
if (anyOffspringLocusTested == false){
if (neuralNetworkExists == false){
// We cannot analyze this disease
return nil
}
if (anyOffspringLocusKnown == false){
// We have no information about this genome pair's disease risk
// We don't add this genome pair's disease info to the diseaseInfoMap
return nil
@ -542,10 +544,11 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
newOffspringGenomePairPolygenicDiseaseInfo := geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo{
QuantityOfLociTested: quantityOfLociTested,
OffspringAverageRiskScore: genomePairOffspringAverageRiskScore,
LociInfoMap: genomePairOffspringDiseaseLociInfoMap,
SampleOffspringRiskScoresList: genomePairSampleOffspringRiskScoresList,
OffspringAverageRiskScore: offspringAverageRiskScore,
PredictionConfidenceRangesMap: accuracyRangesMap,
QuantityOfLociKnown: quantityOfLociKnown,
QuantityOfParentalPhasedLoci: quantityOfParentalPhasedLoci,
SampleOffspringRiskScoresList: predictedRiskScoresList,
}
genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier)
@ -564,6 +567,11 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
if (err != nil) { return false, "", err }
}
if (len(offspringPolygenicDiseaseInfoMap) == 0){
// No disease analysis was performed
continue
}
newOffspringPolygenicDiseaseInfoObject := geneticAnalysis.OffspringPolygenicDiseaseInfo{
PolygenicDiseaseInfoMap: offspringPolygenicDiseaseInfoMap,
}
@ -644,7 +652,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
newOffspringGenomePairTraitInfo := geneticAnalysis.OffspringGenomePairDiscreteTraitInfo{}
neuralNetworkExists, neuralNetworkAnalysisExists, outcomeProbabilitiesMap, averagePredictionConfidence, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject, person1LocusValuesMap, person2LocusValuesMap)
neuralNetworkExists, neuralNetworkAnalysisExists, outcomeProbabilitiesMap, averagePredictionConfidence, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringDiscreteTraitAnalysis_NeuralNetwork(traitObject, person1LocusValuesMap, person2LocusValuesMap)
if (err != nil) { return err }
if (neuralNetworkExists == true){
@ -665,7 +673,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
}
}
anyRulesExist, rulesAnalysisExists, quantityOfRulesTested, quantityOfLociKnown, offspringProbabilityOfPassingRulesMap, offspringOutcomeProbabilitiesMap, err := GetOffspringDiscreteTraitInfo_Rules(traitObject, person1LocusValuesMap, person2LocusValuesMap)
anyRulesExist, rulesAnalysisExists, quantityOfRulesTested, quantityOfLociKnown, offspringProbabilityOfPassingRulesMap, offspringOutcomeProbabilitiesMap, err := GetOffspringDiscreteTraitAnalysis_Rules(traitObject, person1LocusValuesMap, person2LocusValuesMap)
if (err != nil) { return err }
if (anyRulesExist == true){
@ -764,7 +772,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
return errors.New("addGenomePairTraitInfoToOffspringMap called with unknown person2GenomeIdentifier.")
}
neuralNetworkExists, neuralNetworkAnalysisExists, averageOutcome, predictionConfidenceRangesMap, sampleOffspringOutcomesList, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringNumericTraitInfo(traitObject, person1LocusValuesMap, person2LocusValuesMap)
neuralNetworkExists, neuralNetworkAnalysisExists, averageOutcome, predictionConfidenceRangesMap, sampleOffspringOutcomesList, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringNumericTraitAnalysis(traitObject, person1LocusValuesMap, person2LocusValuesMap)
if (err != nil) { return err }
if (neuralNetworkExists == false){
// Predictions are not possible for this trait
@ -951,288 +959,109 @@ func GetOffspringMonogenicDiseaseProbabilities(dominantOrRecessive string, perso
return true, percentageProbabilityOffspringHasDiseaseInt, true, percentageProbabilityOffspringHasVariantInt, nil
}
// This is used to calculate user polygenic disease info for users
// It is faster to do it this way, because we don't create 100 prospective offspring
// We instead create 4 outcomes for each locus
// We can do this because testing each locus's risk score is independent of every other locus
// This is not true for traits, because trait rules are effected by multiple different loci
// When using the fast method for polygenic diseases, we don't get a sample of 100 offspring disease risk scores.
// The average risk score should still be the same for the fast and normal methods
// This function is also faster because we don't calculate odds ratio information or information about each locus
//Outputs:
// -bool: Any loci tested (if false, no offspring polygenic disease information is known)
// -int: Offspring Risk Score (Value between 0-10)
// -int: Number of loci tested
// -error
func GetOffspringPolygenicDiseaseInfo_Fast(diseaseLociList []polygenicDiseases.DiseaseLocus, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, int, int, error){
if (len(person1LocusValuesMap) == 0){
return false, 0, 0, nil
}
if (len(person2LocusValuesMap) == 0){
return false, 0, 0, nil
}
// I = Insertion
// D = Deletion
validAllelesList := []string{"C", "A", "T", "G", "I", "D"}
numberOfLociTested := 0
offspringSummedRiskWeights := 0
offspringMinimumPossibleRiskWeightSum := 0
offspringMaximumPossibleRiskWeightSum := 0
for _, locusObject := range diseaseLociList{
locusRSID := locusObject.LocusRSID
locusRiskWeightsMap := locusObject.RiskWeightsMap
locusMinimumWeight := locusObject.MinimumRiskWeight
locusMaximumWeight := locusObject.MaximumRiskWeight
person1LocusValueFound, person1LocusBase1Value, person1LocusBase2Value, _, _, err := createPersonGeneticAnalysis.GetLocusValueFromGenomeMap(true, person1LocusValuesMap, locusRSID)
if (err != nil) { return false, 0, 0, err }
if (person1LocusValueFound == false){
// None of the offspring will have a value for this locus
continue
}
person2LocusValueFound, person2LocusBase1Value, person2LocusBase2Value, _, _, err := createPersonGeneticAnalysis.GetLocusValueFromGenomeMap(true, person2LocusValuesMap, locusRSID)
if (err != nil) { return false, 0, 0, err }
if (person2LocusValueFound == false){
// None of the offspring will have a value for this locus
continue
}
baseIsValid := slices.Contains(validAllelesList, person1LocusBase1Value)
if (baseIsValid == false){
return false, 0, 0, errors.New("GetOffspringPolygenicDiseaseInfo_Fast called with genomeMap containing invalid locus value base: " + person1LocusBase1Value)
}
baseIsValid = slices.Contains(validAllelesList, person1LocusBase2Value)
if (baseIsValid == false){
return false, 0, 0, errors.New("GetOffspringPolygenicDiseaseInfo_Fast called with genomeMap containing invalid locus value base: " + person1LocusBase2Value)
}
baseIsValid = slices.Contains(validAllelesList, person2LocusBase1Value)
if (baseIsValid == false){
return false, 0, 0, errors.New("GetOffspringPolygenicDiseaseInfo_Fast called with genomeMap containing invalid locus value base: " + person2LocusBase1Value)
}
baseIsValid = slices.Contains(validAllelesList, person2LocusBase2Value)
if (baseIsValid == false){
return false, 0, 0, errors.New("GetOffspringPolygenicDiseaseInfo_Fast called with genomeMap containing invalid locus value base: " + person2LocusBase2Value)
}
numberOfLociTested += 1
offspringBasePairOutcome1 := person1LocusBase1Value + ";" + person2LocusBase1Value
offspringBasePairOutcome2 := person1LocusBase2Value + ";" + person2LocusBase2Value
offspringBasePairOutcome3 := person1LocusBase1Value + ";" + person2LocusBase2Value
offspringBasePairOutcome4 := person1LocusBase2Value + ";" + person2LocusBase1Value
baseOutcomesList := []string{offspringBasePairOutcome1, offspringBasePairOutcome2, offspringBasePairOutcome3, offspringBasePairOutcome4}
outcomesSummedRiskWeight := 0
for _, outcomeBasePair := range baseOutcomesList{
offspringOutcomeRiskWeight, exists := locusRiskWeightsMap[outcomeBasePair]
if (exists == false){
// We do not know the risk weight for this base pair
// We treat this as a 0 risk weight
continue
}
outcomesSummedRiskWeight += offspringOutcomeRiskWeight
}
locusAverageRiskWeight := outcomesSummedRiskWeight/4
offspringSummedRiskWeights += locusAverageRiskWeight
offspringMinimumPossibleRiskWeightSum += locusMinimumWeight
offspringMaximumPossibleRiskWeightSum += locusMaximumWeight
}
offspringAverageDiseaseRiskScore, err := helpers.ScaleIntProportionally(true, offspringSummedRiskWeights, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10)
if (err != nil) { return false, 0, 0, err }
if (numberOfLociTested == 0){
// No locations were tested
return false, 0, 0, nil
}
return true, offspringAverageDiseaseRiskScore, numberOfLociTested, nil
}
//Outputs:
// -bool: Any loci tested (if false, no offspring polygenic disease information is known)
// -int: Offspring Risk Score (Value between 0-10)
// -int: Number of loci tested
// -map[[3]byte]geneticAnalysis.OffspringPolygenicDiseaseLocusInfo: Offspring Locus information map
// Map Structure: Locus identifier -> OffspringPolygenicDiseaseLocusInfo
// -bool: A neural network exists for this trait
// -bool: Any loci tested (if false, no offspring polygenic disease analysis is known)
// -int: Offspring Average Risk Score (Value between 0-10)
// -map[int]float64: Prediction accuracy ranges map
// -Map Structure: Probability prediction is accurate (X) -> Distance from prediction that must be travelled in both directions to
// create a range in which the true value will fall into, X% of the time
// -[]int: Sample offspring risks scores list
// -int: Quantity of loci known
// -int: Quantity of parental phased loci
// -error
func GetOffspringPolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.DiseaseLocus, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, int, int, map[[3]byte]geneticAnalysis.OffspringPolygenicDiseaseLocusInfo, []int, error){
func GetOffspringPolygenicDiseaseAnalysis(diseaseObject polygenicDiseases.PolygenicDisease, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, int, map[int]float64, []int, int, int, error){
diseaseName := diseaseObject.DiseaseName
modelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(diseaseName)
if (modelExists == false){
// Prediction is not possible for this trait
return false, false, 0, nil, nil, 0, 0, nil
}
if (len(person1LocusValuesMap) == 0){
return false, 0, 0, nil, nil, nil
return true, false, 0, nil, nil, 0, 0, nil
}
if (len(person2LocusValuesMap) == 0){
return false, 0, 0, nil, nil, nil
return true, false, 0, nil, nil, 0, 0, nil
}
// First, we create 100 prospective offspring genomes.
diseaseLociList := diseaseObject.LociList
diseaseLociRSIDsList := make([]int64, 0)
// First we count up the quantity of parental phased loci
// We only count the quantity of phased loci for loci which are known for both parents
for _, diseaseLocusObject := range diseaseLociList{
quantityOfParentalPhasedLoci := 0
locusRSID := diseaseLocusObject.LocusRSID
diseaseLociRSIDsList = append(diseaseLociRSIDsList, locusRSID)
}
for _, rsID := range diseaseLociList{
anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(diseaseLociRSIDsList, person1LocusValuesMap, person2LocusValuesMap)
if (err != nil) { return false, 0, 0, nil, nil, err }
if (anyLocusValueExists == false){
return false, 0, 0, nil, nil, nil
}
// This will sum every offspring's average disease risk score
offspringAverageRiskScoreSum := 0
// This stores a list of every prospective offspring's risk score
sampleOffspringRiskScoresList := make([]int, 0)
type offspringSummedLocusInfoObject struct{
SummedLocusRiskWeights int
SummedOddsRatios float64
NumberOfSummedOddsRatios int
// This is the number of unknown-odds-ratio-weight sums that we summed up
NumberOfUnknownOddsRatioWeightSums int
// This is the sum of every unknown-odds-ratio-weight-sum for each prospective offspring for this genome
UnknownOddsRatioWeightSumsSummed int
}
// Map Structure: Locus Identifier -> offspringSummedLocusInfoObject
offspringLocusInfoSumsMap := make(map[[3]byte]offspringSummedLocusInfoObject)
for offspringIndex, offspringGenomeMap := range prospectiveOffspringGenomesList{
offspringSummedRiskWeights := 0
offspringMinimumPossibleRiskWeightSum := 0
offspringMaximumPossibleRiskWeightSum := 0
for _, locusObject := range diseaseLociList{
locusIdentifierHex := locusObject.LocusIdentifier
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
if (err != nil) { return false, 0, 0, nil, nil, err }
offspringLocusInfoSumsObject, exists := offspringLocusInfoSumsMap[locusIdentifier]
person1LocusValue, exists := person1LocusValuesMap[rsID]
if (exists == false){
if (offspringIndex != 0){
// We already checked a previous offspring for this locus, and it's value doesn't exist
continue
}
}
locusRSID := locusObject.LocusRSID
locusRiskWeightsMap := locusObject.RiskWeightsMap
locusOddsRatiosMap := locusObject.OddsRatiosMap
locusMinimumWeight := locusObject.MinimumRiskWeight
locusMaximumWeight := locusObject.MaximumRiskWeight
basePairValueFound, locusBase1Value, locusBase2Value, _, _, err := createPersonGeneticAnalysis.GetLocusValueFromGenomeMap(true, offspringGenomeMap, locusRSID)
if (err != nil) { return false, 0, 0, nil, nil, err }
if (basePairValueFound == false){
// None of the offspring will have a value for this locus
continue
}
locusRiskWeight, locusOddsRatioIsKnown, locusOddsRatio, err := createPersonGeneticAnalysis.GetGenomePolygenicDiseaseLocusRiskInfo(locusRiskWeightsMap, locusOddsRatiosMap, locusBase1Value, locusBase2Value)
if (err != nil) { return false, 0, 0, nil, nil, err }
offspringLocusInfoSumsObject.SummedLocusRiskWeights += locusRiskWeight
if (locusOddsRatioIsKnown == true){
offspringLocusInfoSumsObject.SummedOddsRatios += locusOddsRatio
offspringLocusInfoSumsObject.NumberOfSummedOddsRatios += 1
} else {
offspringLocusInfoSumsObject.UnknownOddsRatioWeightSumsSummed += locusRiskWeight
offspringLocusInfoSumsObject.NumberOfUnknownOddsRatioWeightSums += 1
person2LocusValue, exists := person2LocusValuesMap[rsID]
if (exists == false){
continue
}
offspringLocusInfoSumsMap[locusIdentifier] = offspringLocusInfoSumsObject
offspringSummedRiskWeights += locusRiskWeight
offspringMinimumPossibleRiskWeightSum += locusMinimumWeight
offspringMaximumPossibleRiskWeightSum += locusMaximumWeight
person1LocusIsPhased := person1LocusValue.LocusIsPhased
if (person1LocusIsPhased == true){
quantityOfParentalPhasedLoci += 1
}
offspringAverageDiseaseRiskScore, err := helpers.ScaleIntProportionally(true, offspringSummedRiskWeights, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10)
if (err != nil) { return false, 0, 0, nil, nil, err }
sampleOffspringRiskScoresList = append(sampleOffspringRiskScoresList, offspringAverageDiseaseRiskScore)
offspringAverageRiskScoreSum += offspringAverageDiseaseRiskScore
person2LocusIsPhased := person2LocusValue.LocusIsPhased
if (person2LocusIsPhased == true){
quantityOfParentalPhasedLoci += 1
}
}
numberOfLociTested := len(offspringLocusInfoSumsMap)
// We create 100 prospective offspring genomes.
if (numberOfLociTested == 0){
// No locations were tested
return false, 0, 0, nil, nil, nil
anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(diseaseLociList, person1LocusValuesMap, person2LocusValuesMap)
if (err != nil) { return false, false, 0, nil, nil, 0, 0, err }
if (anyLocusValueExists == false){
return true, false, 0, nil, nil, 0, 0, nil
}
offspringAverageRiskScore := offspringAverageRiskScoreSum/100
// A list of predicted risk scores for each offspring
predictedRiskScoresList := make([]int, 0)
// Map Structure: Locus Identifier -> OffspringPolygenicDiseaseLocusInfo
offspringDiseaseLociInfoMap := make(map[[3]byte]geneticAnalysis.OffspringPolygenicDiseaseLocusInfo)
accuracyRangesMap := make(map[int]float64)
quantityOfLociTested := 0
for locusIdentifier, summedLocusInfoObject := range offspringLocusInfoSumsMap{
for index, offspringGenomeMap := range prospectiveOffspringGenomesList{
summedLocusRiskWeights := summedLocusInfoObject.SummedLocusRiskWeights
summedOddsRatios := summedLocusInfoObject.SummedOddsRatios
numberOfSummedOddsRatios := summedLocusInfoObject.NumberOfSummedOddsRatios
numberOfUnknownOddsRatioWeightSums := summedLocusInfoObject.NumberOfUnknownOddsRatioWeightSums
unknownOddsRatioWeightSumsSummed := summedLocusInfoObject.UnknownOddsRatioWeightSumsSummed
// There are 100 prospective offspring, so we divide by 100
locusAverageRiskWeight := summedLocusRiskWeights/100
newLocusInfoObject := geneticAnalysis.OffspringPolygenicDiseaseLocusInfo{
OffspringAverageRiskWeight: locusAverageRiskWeight,
neuralNetworkExists, predictionIsKnown, predictedRiskScore, predictionAccuracyRangesMap, currentQuantityOfLociTested, _, err := createPersonGeneticAnalysis.GetPersonGenomePolygenicDiseaseAnalysis(diseaseObject, offspringGenomeMap, false)
if (err != nil){ return false, false, 0, nil, nil, 0, 0, err }
if (neuralNetworkExists == false){
return false, false, 0, nil, nil, 0, 0, errors.New("GetGenomeNumericTraitAnalysis claiming that neural network doesn't exist when we already checked.")
}
if (predictionIsKnown == false){
return false, false, 0, nil, nil, 0, 0, errors.New("GetGenomeNumericTraitAnalysis claiming that prediction is impossible when we already know at least 1 locus value exists for trait.")
}
if (numberOfSummedOddsRatios != 0){
newLocusInfoObject.OffspringOddsRatioIsKnown = true
predictedRiskScoresList = append(predictedRiskScoresList, predictedRiskScore)
offspringAverageOddsRatio := summedOddsRatios/float64(numberOfSummedOddsRatios)
newLocusInfoObject.OffspringAverageOddsRatio = offspringAverageOddsRatio
if (index == 0){
// These values should be the same for each predicted offspring
accuracyRangesMap = predictionAccuracyRangesMap
quantityOfLociTested = currentQuantityOfLociTested
}
}
if (numberOfUnknownOddsRatioWeightSums != 0){
// We calculate the average predicted risk score
offspringAverageUnknownOddsRatiosWeightSum := unknownOddsRatioWeightSumsSummed/numberOfUnknownOddsRatioWeightSums
outcomesSum := 0
newLocusInfoObject.OffspringAverageUnknownOddsRatiosWeightSum = offspringAverageUnknownOddsRatiosWeightSum
for _, predictedRiskScore := range predictedRiskScoresList{
outcomesSum += predictedRiskScore
}
offspringDiseaseLociInfoMap[locusIdentifier] = newLocusInfoObject
}
averageRiskScore := outcomesSum/100
return true, offspringAverageRiskScore, numberOfLociTested, offspringDiseaseLociInfoMap, sampleOffspringRiskScoresList, nil
return true, true, averageRiskScore, accuracyRangesMap, predictedRiskScoresList, quantityOfLociTested, quantityOfParentalPhasedLoci, nil
}
@ -1245,13 +1074,13 @@ func GetOffspringPolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.Diseas
// -int: Quantity of loci tested
// -int: Quantity of parental phased loci
// -error
func GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, map[string]int, int, int, int, error){
func GetOffspringDiscreteTraitAnalysis_NeuralNetwork(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, map[string]int, int, int, int, error){
traitName := traitObject.TraitName
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Discrete"){
return false, false, nil, 0, 0, 0, errors.New("GetOffspringDiscreteTraitInfo_NeuralNetwork called with non-discrete trait.")
return false, false, nil, 0, 0, 0, errors.New("GetOffspringDiscreteTraitAnalysis_NeuralNetwork called with non-discrete trait.")
}
modelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
@ -1343,7 +1172,7 @@ func GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject traits.Trait, perso
// -map[string]int: Offspring outcome probabilities map
// Map Structure: Outcome Name -> Offspring probability of outcome (0-100)
// -error
func GetOffspringDiscreteTraitInfo_Rules(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, int, int, map[[3]byte]int, map[string]int, error){
func GetOffspringDiscreteTraitAnalysis_Rules(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, int, int, map[[3]byte]int, map[string]int, error){
traitRulesList := traitObject.RulesList
@ -1421,7 +1250,6 @@ func GetOffspringDiscreteTraitInfo_Rules(traitObject traits.Trait, person1LocusV
}
//Outputs:
// -bool: A neural network exists for this trait
// -bool: Analysis exists (at least 1 locus exists for this analysis from both people's genomes
@ -1433,13 +1261,13 @@ func GetOffspringDiscreteTraitInfo_Rules(traitObject traits.Trait, person1LocusV
// -int: Quantity of loci known
// -int: Quantity of parental phased loci
// -error
func GetOffspringNumericTraitInfo(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, float64, map[int]float64, []float64, int, int, error){
func GetOffspringNumericTraitAnalysis(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, float64, map[int]float64, []float64, int, int, error){
traitName := traitObject.TraitName
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Numeric"){
return false, false, 0, nil, nil, 0, 0, errors.New("GetOffspringNumericTraitInfo called with non-numeric trait.")
return false, false, 0, nil, nil, 0, 0, errors.New("GetOffspringNumericTraitAnalysis called with non-numeric trait.")
}
modelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)

View file

@ -8,10 +8,6 @@ package createPersonGeneticAnalysis
// Disclaimer: I am a novice in the ways of genetics. This package could be flawed in numerous ways.
// TODO: We want to eventually use neural nets for both trait and polygenic disease analysis (see geneticPrediction.go)
// These will be trained on a set of genomes and will output a probability analysis for each trait/disease
// This is only possible once we get access to the necessary training data
// TODO: Add the ability to weight different genome files based on their reliability.
// Some files are much more accurate because they record each location many times.
@ -667,80 +663,6 @@ func GetPersonMonogenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
return personMonogenicDiseaseInfoObject, nil
}
//Outputs:
// -bool: Any loci tested
// -int: Person genome risk score (value between 0-10)
// -int: Person Genome Number of loci tested
// -map[[3]byte]geneticAnalysis.PersonGenomePolygenicDiseaseLocusInfo: Person disease locus info map
// Map Structure: Locus Identifier -> PersonGenomePolygenicDiseaseLocusInfo
// -error
func GetPersonGenomePolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.DiseaseLocus, personLocusValuesMap map[int64]locusValue.LocusValue, lookForLocusAliases bool)(bool, int, int, map[[3]byte]geneticAnalysis.PersonGenomePolygenicDiseaseLocusInfo, error){
if (len(personLocusValuesMap) == 0){
return false, 0, 0, nil, nil
}
// Map Structure: Locus Identifier -> PersonGenomePolygenicDiseaseLocusInfo
genomeLociInfoMap := make(map[[3]byte]geneticAnalysis.PersonGenomePolygenicDiseaseLocusInfo)
summedDiseaseRiskWeight := 0
minimumPossibleRiskWeightSum := 0
maximumPossibleRiskWeightSum := 0
for _, locusObject := range diseaseLociList{
locusRSID := locusObject.LocusRSID
locusRiskWeightsMap := locusObject.RiskWeightsMap
locusOddsRatiosMap := locusObject.OddsRatiosMap
locusMinimumWeight := locusObject.MinimumRiskWeight
locusMaximumWeight := locusObject.MaximumRiskWeight
locusValueFound, locusBase1Value, locusBase2Value, _, _, err := GetLocusValueFromGenomeMap(lookForLocusAliases, personLocusValuesMap, locusRSID)
if (err != nil) { return false, 0, 0, nil, err }
if (locusValueFound == false){
continue
}
locusRiskWeight, locusOddsRatioIsKnown, locusOddsRatio, err := GetGenomePolygenicDiseaseLocusRiskInfo(locusRiskWeightsMap, locusOddsRatiosMap, locusBase1Value, locusBase2Value)
if (err != nil) { return false, 0, 0, nil, err }
newLocusInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseLocusInfo{
RiskWeight: locusRiskWeight,
OddsRatioIsKnown: locusOddsRatioIsKnown,
}
if (locusOddsRatioIsKnown == true){
newLocusInfoObject.OddsRatio = locusOddsRatio
}
locusIdentifierHex := locusObject.LocusIdentifier
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
if (err != nil) { return false, 0, 0, nil, err }
genomeLociInfoMap[locusIdentifier] = newLocusInfoObject
minimumPossibleRiskWeightSum += locusMinimumWeight
maximumPossibleRiskWeightSum += locusMaximumWeight
summedDiseaseRiskWeight += locusRiskWeight
}
numberOfLociTested := len(genomeLociInfoMap)
if (numberOfLociTested == 0){
// We have no information about this disease for this genome
return false, 0, 0, nil, nil
}
diseaseRiskScore, err := helpers.ScaleIntProportionally(true, summedDiseaseRiskWeight, minimumPossibleRiskWeightSum, maximumPossibleRiskWeightSum, 0, 10)
if (err != nil) { return false, 0, 0, nil, err }
return true, diseaseRiskScore, numberOfLociTested, genomeLociInfoMap, nil
}
//Outputs:
// -geneticAnalysis.PersonPolygenicDiseaseInfo
// -error
@ -749,8 +671,6 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
// We use this when returning errors
emptyDiseaseInfoObject := geneticAnalysis.PersonPolygenicDiseaseInfo{}
diseaseLociList := diseaseObject.LociList
// This map stores the polygenic disease for each of the person's genomes
// Map Structure: Genome Identifier -> PersonGenomePolygenicDiseaseInfo
personPolygenicDiseaseInfoMap := make(map[[16]byte]geneticAnalysis.PersonGenomePolygenicDiseaseInfo)
@ -762,33 +682,17 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
genomeIdentifier := genomeWithMetadataObject.GenomeIdentifier
genomeMap := genomeWithMetadataObject.GenomeMap
// This map stores the loci for this disease and does not contain loci which do not belong to this disease
// Map Structure: rsID -> Locus Value
genomeLocusValuesMap := make(map[int64]locusValue.LocusValue)
for _, locusObject := range diseaseLociList{
locusRSID := locusObject.LocusRSID
locusValueFound, _, _, _, locusValueObject, err := GetLocusValueFromGenomeMap(true, genomeMap, locusRSID)
neuralNetworkExists, anyLociTested, personDiseaseRiskScore, predictionAccuracyRangesMap, genomeQuantityOfLociKnown, genomeQuantityOfPhasedLoci, err := GetPersonGenomePolygenicDiseaseAnalysis(diseaseObject, genomeMap, true)
if (err != nil) { return emptyDiseaseInfoObject, err }
if (locusValueFound == false){
continue
}
genomeLocusValuesMap[locusRSID] = locusValueObject
}
anyLociTested, personDiseaseRiskScore, genomeNumberOfLociTested, genomeLociInfoMap, err := GetPersonGenomePolygenicDiseaseInfo(diseaseLociList, genomeLocusValuesMap, true)
if (err != nil) { return emptyDiseaseInfoObject, err }
if (anyLociTested == false){
if (neuralNetworkExists == false || anyLociTested == false){
continue
}
newDiseaseInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseInfo{
QuantityOfLociTested: genomeNumberOfLociTested,
RiskScore: personDiseaseRiskScore,
LociInfoMap: genomeLociInfoMap,
ConfidenceRangesMap: predictionAccuracyRangesMap,
QuantityOfLociKnown: genomeQuantityOfLociKnown,
QuantityOfPhasedLoci: genomeQuantityOfPhasedLoci,
}
personPolygenicDiseaseInfoMap[genomeIdentifier] = newDiseaseInfoObject
@ -810,75 +714,20 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
// First we check to see if any of the genomes have different risk scores or NumberOfLociTested
genomeRiskScore := 0
genomeNumberOfLociTested := 0
personGenomePolygenicDiseaseInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseInfo{}
firstItemReached := false
for _, personGenomeDiseaseInfoObject := range personPolygenicDiseaseInfoMap{
currentGenomeRiskScore := personGenomeDiseaseInfoObject.RiskScore
currentGenomeNumberOfLociTested := personGenomeDiseaseInfoObject.QuantityOfLociTested
if (firstItemReached == false){
genomeRiskScore = currentGenomeRiskScore
genomeNumberOfLociTested = currentGenomeNumberOfLociTested
personGenomePolygenicDiseaseInfoObject = personGenomeDiseaseInfoObject
firstItemReached = true
continue
}
if (genomeRiskScore != currentGenomeRiskScore){
return true, nil
}
if (genomeNumberOfLociTested != currentGenomeNumberOfLociTested){
return true, nil
}
}
// Now we check for conflicts between the different locus values
// We consider a conflict any time the same locus has different weights/odds ratios
// We don't care if the loci have different base pair values, so long as those base pairs have the same risk weights/odds ratios
for _, locusObject := range diseaseLociList{
locusIdentifierHex := locusObject.LocusIdentifier
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
if (err != nil) { return false, err }
locusRiskWeight := 0
locusOddsRatio := float64(0)
firstItemReached := false
for _, personGenomeDiseaseInfoObject := range personPolygenicDiseaseInfoMap{
genomeLociInfoMap := personGenomeDiseaseInfoObject.LociInfoMap
genomeLocusObject, exists := genomeLociInfoMap[locusIdentifier]
if (exists == false){
if (firstItemReached == true){
// A previous genome has information for this locus, and the current one does not
return true, nil
}
continue
}
genomeLocusRiskWeight := genomeLocusObject.RiskWeight
genomeLocusOddsRatio := genomeLocusObject.OddsRatio
if (firstItemReached == false){
locusRiskWeight = genomeLocusRiskWeight
locusOddsRatio = genomeLocusOddsRatio
firstItemReached = true
continue
}
if (locusRiskWeight == genomeLocusRiskWeight && locusOddsRatio == genomeLocusOddsRatio){
// No conflict exists for this locus on the genomes we have already checked
continue
}
// Conflict exists
areEqual := reflect.DeepEqual(personGenomeDiseaseInfoObject, personGenomePolygenicDiseaseInfoObject)
if (areEqual == false){
return true, nil
}
}
@ -895,6 +744,67 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
}
//Outputs:
// -bool: Neural network exists for disease
// -bool: Any loci tested
// -int: Person genome risk score (value between 0-10)
// -map[int]float64: Confidence ranges map
// -If we want to know how accurate the prediction is with a X% accuracy, how far would we have to expand the
// risk score's range to be accurate, X% of the time?
// -Map Structure: Percentage -> Distance to travel in both directions of prediction
// -int: Person Genome quantity of loci known
// -int: Person genome quantity of phased loci
// -error
func GetPersonGenomePolygenicDiseaseAnalysis(diseaseObject polygenicDiseases.PolygenicDisease, personGenomeMap map[int64]locusValue.LocusValue, checkForAliases bool)(bool, bool, int, map[int]float64, int, int, error){
diseaseLociList := diseaseObject.LociList
getGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
if (checkForAliases == false){
// We don't need to check for rsID aliases.
return personGenomeMap, nil
}
// This map contains the locus values for the genome
// If a locus's entry doesn't exist, its value is unknown
// Map Structure: Locus rsID -> Locus Value
genomeLocusValuesMap := make(map[int64]locusValue.LocusValue)
for _, locusRSID := range diseaseLociList{
locusBasePairKnown, _, _, _, locusValueObject, err := GetLocusValueFromGenomeMap(checkForAliases, personGenomeMap, locusRSID)
if (err != nil) { return nil, err }
if (locusBasePairKnown == false){
continue
}
genomeLocusValuesMap[locusRSID] = locusValueObject
}
return genomeLocusValuesMap, nil
}
genomeLocusValuesMap, err := getGenomeLocusValuesMap()
if (err != nil) { return false, false, 0, nil, 0, 0, err }
diseaseName := diseaseObject.DiseaseName
neuralNetworkModelExists, riskScorePredictionIsPossible, predictedRiskScore, predictionAccuracyRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, err := geneticPrediction.GetNeuralNetworkNumericAttributePredictionFromGenomeMap(diseaseName, diseaseLociList, genomeLocusValuesMap)
if (err != nil) { return false, false, 0, nil, 0, 0, err }
if (neuralNetworkModelExists == false){
return false, false, 0, nil, 0, 0, nil
}
if (riskScorePredictionIsPossible == false){
return true, false, 0, nil, 0, 0, nil
}
predictedRiskScoreInt := int(predictedRiskScore)
return true, true, predictedRiskScoreInt, predictionAccuracyRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, nil
}
//Outputs:
// -geneticAnalysis.PersonDiscreteTraitInfo: Trait analysis object
// -error
@ -1073,35 +983,6 @@ func GetPersonNumericTraitAnalysis(inputGenomesWithMetadataList []prepareRawGeno
return newPersonTraitInfoObject, nil
}
//Outputs:
// -int: Base pair disease locus risk weight
// -bool: Base pair disease locus odds ratio known
// -float64: Base pair disease locus odds ratio
// -error
func GetGenomePolygenicDiseaseLocusRiskInfo(locusRiskWeightsMap map[string]int, locusOddsRatiosMap map[string]float64, locusBase1Value string, locusBase2Value string)(int, bool, float64, error){
locusBasePairJoined := locusBase1Value + ";" + locusBase2Value
riskWeight, exists := locusRiskWeightsMap[locusBasePairJoined]
if (exists == false){
// This is an unknown base combination
// We will treat it as a 0 risk weight
return 0, true, 1, nil
}
if (riskWeight == 0){
return 0, true, 1, nil
}
oddsRatio, exists := locusOddsRatiosMap[locusBasePairJoined]
if (exists == false){
return riskWeight, false, 0, nil
}
return riskWeight, true, oddsRatio, nil
}
// We use this to generate discrete trait predictions using a neural network
// The alternative prediction method is to use Rules (see GetGenomeTraitAnalysis_Rules)
//Outputs:
@ -1357,6 +1238,8 @@ func GetGenomePassesDiscreteTraitRuleStatus(ruleLociList []traits.RuleLocus, gen
// -error
func GetGenomeNumericTraitAnalysis(traitObject traits.Trait, genomeMap map[int64]locusValue.LocusValue, checkForAliases bool)(bool, bool, float64, map[int]float64, int, int, error){
traitLociList := traitObject.LociList
getGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
if (checkForAliases == false){
@ -1364,8 +1247,6 @@ func GetGenomeNumericTraitAnalysis(traitObject traits.Trait, genomeMap map[int64
return genomeMap, nil
}
traitLociList := traitObject.LociList
// This map contains the locus values for the genome
// If a locus's entry doesn't exist, its value is unknown
// Map Structure: Locus rsID -> Locus Value
@ -1390,7 +1271,7 @@ func GetGenomeNumericTraitAnalysis(traitObject traits.Trait, genomeMap map[int64
traitName := traitObject.TraitName
neuralNetworkModelExists, traitPredictionIsPossible, predictedOutcome, predictionAccuracyRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, err := geneticPrediction.GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName, genomeLocusValuesMap)
neuralNetworkModelExists, traitPredictionIsPossible, predictedOutcome, predictionAccuracyRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, err := geneticPrediction.GetNeuralNetworkNumericAttributePredictionFromGenomeMap(traitName, traitLociList, genomeLocusValuesMap)
if (err != nil) { return false, false, 0, nil, 0, 0, err }
if (neuralNetworkModelExists == false){
return false, false, 0, nil, 0, 0, nil

View file

@ -107,32 +107,21 @@ type PersonPolygenicDiseaseInfo struct{
type PersonGenomePolygenicDiseaseInfo struct{
// This describes the quantity of loci tested for this disease
// This should be len(LociInfoMap)
QuantityOfLociTested int
// This is total risk score for this disease for the person's genome
// This is a number between 1-10
RiskScore int
// This map contains info about all tested polygenic disease loci for this genome
// If a locus does not exist in the map, its values are unknown
// Map Structure: Locus Identifier -> PersonGenomePolygenicDiseaseLocusInfo
LociInfoMap map[[3]byte]PersonGenomePolygenicDiseaseLocusInfo
}
// This map stores the confidence ranges for the predicted risk score
// If we want to know how accurate the prediction is with a X% accuracy, how far would we have to expand the
// risk score's range to be accurate, X% of the time?
// For example: 50% accuracy requires a +/-2 point range, 80% accuracy requires a +-5 point range
// Map Structure: Accuracy probability (0-100) -> Amount to add to value in both +/- directions so prediction is that accurate
ConfidenceRangesMap map[int]float64
type PersonGenomePolygenicDiseaseLocusInfo struct{
// This describes the quantity of loci tested for this disease
QuantityOfLociKnown int
// This is the risk weight that this person's genome has for this variant
// A higher risk weight means more risk of getting the disease
RiskWeight int
// This is valse if the odds ratio is not known
OddsRatioIsKnown bool
// This is the person's genome odds ratio value for this variant's locus
// A ratio >1 means their risk is increased, a ratio <1 means their risk is decreased
OddsRatio float64
QuantityOfPhasedLoci int
}
@ -325,7 +314,6 @@ type OffspringMonogenicDiseaseVariantInfo struct{
ProbabilityOf2MutationsUpperBound int
}
type OffspringPolygenicDiseaseInfo struct{
// This map stores the polygenic disease info for each genome pair
@ -339,16 +327,23 @@ type OffspringPolygenicDiseaseInfo struct{
type OffspringGenomePairPolygenicDiseaseInfo struct{
// This should be len(LociInfoMap)
QuantityOfLociTested int
// A number between 1-10 representing the offspring's average risk score
// 1 == lowest risk, 10 == highest risk
OffspringAverageRiskScore int
// A map of the offspring's locus information
// Map Structure: Locus Identifier -> OffspringPolygenicDiseaseLocusInfo
LociInfoMap map[[3]byte]OffspringPolygenicDiseaseLocusInfo
// This map stores the confidence ranges for the predicted risk score
// If we want to know how accurate the prediction is with a X% accuracy, how far would we have to expand the
// risk score's range to be accurate, X% of the time?
// For example: 50% accuracy requires a +/-2 point range, 80% accuracy requires a +-3 point range
// Map Structure: Accuracy probability (0-100) -> Amount to add to value in both +/- directions so prediction is that accurate
PredictionConfidenceRangesMap map[int]float64
QuantityOfLociKnown int
// This describes the quantity of loci from both parents that are phased
// For example, if there are 10 loci for this trait, and one parent has 10 phased loci and the other has 5,
// this variable will have a value of 15
QuantityOfParentalPhasedLoci int
// This is a list of prospective offspring risk scores
// This is useful for plotting on a graph to understand the standard deviation of risk
@ -356,27 +351,6 @@ type OffspringGenomePairPolygenicDiseaseInfo struct{
}
type OffspringPolygenicDiseaseLocusInfo struct{
// This is the offspring's average risk weight for this locus value
// A higher weight means a higher risk of the disease
OffspringAverageRiskWeight int
// This is true if any of the 100 prospective offspring had a known odds ratio for this locus
OffspringOddsRatioIsKnown bool
// This value represent's the offspring's average odds ratio for the disease locus
// A value <1 denotes a lesser risk, a value >1 denotes an increased risk
OffspringAverageOddsRatio float64
// This is the average of the sum of weights for the loci which have no odds ratios for each prospective offspring
// We do this to understand what effect those loci are having on the odds ratio
// If the sum is <0, we say the ratio is probably lower
// If the sum is >0, we say the ratio is probably higher
OffspringAverageUnknownOddsRatiosWeightSum int
}
type OffspringDiscreteTraitInfo struct{
// This map stores the trait info for each genome pair

View file

@ -1,6 +1,6 @@
// geneticPrediction provides functions to train and query neural network models
// These models are currently used to predict traits such as eye color from user genome files
// These models are used to predict attributes such as eye color and autism from user genome files
package geneticPrediction
@ -10,6 +10,7 @@ package geneticPrediction
// Sorting matches by offspring total polygenic disease score will require inference on dozens of models for each match
// We could create slower models that provide more accurate predictions
import "seekia/resources/geneticReferences/polygenicDiseases"
import "seekia/resources/geneticReferences/traits"
import "seekia/resources/geneticPredictionModels"
@ -48,7 +49,7 @@ type NeuralNetwork struct{
// and the OutputLayer is a column representing their phenotype, such as eye color
type TrainingData struct{
// InputLayer stores relevant rsID values for each trait from the user's genomes
// InputLayer stores relevant rsID values for each attribute from the user's genomes
// It also stores if each rsID is phased and if each rsID exists
InputLayer []float32
@ -282,9 +283,9 @@ func DecodeBytesToDiscreteTraitPredictionAccuracyInfoMap(inputBytes []byte)(Disc
return newDiscreteTraitPredictionAccuracyInfoMap, nil
}
type NumericTraitPredictionAccuracyInfoMap map[NumericTraitPredictionInfo]NumericTraitPredictionAccuracyRangesMap
type NumericAttributePredictionAccuracyInfoMap map[NumericAttributePredictionInfo]NumericAttributePredictionAccuracyRangesMap
type NumericTraitPredictionInfo struct{
type NumericAttributePredictionInfo struct{
// This is a value between 0-100 which describes the percentage of the loci which were tested for the input for the prediction
PercentageOfLociTested int
@ -302,10 +303,10 @@ type NumericTraitPredictionInfo struct{
// the true height value will fall into this range 90% of the time.
// -50%+: 20 centimeters
// -10%+: 10 centimeters
type NumericTraitPredictionAccuracyRangesMap map[int]float64
type NumericAttributePredictionAccuracyRangesMap map[int]float64
func EncodeNumericTraitPredictionAccuracyInfoMapToBytes(inputMap NumericTraitPredictionAccuracyInfoMap)([]byte, error){
func EncodeNumericAttributePredictionAccuracyInfoMapToBytes(inputMap NumericAttributePredictionAccuracyInfoMap)([]byte, error){
buffer := new(bytes.Buffer)
@ -319,22 +320,22 @@ func EncodeNumericTraitPredictionAccuracyInfoMapToBytes(inputMap NumericTraitPre
return inputMapBytes, nil
}
func DecodeBytesToNumericTraitPredictionAccuracyInfoMap(inputBytes []byte)(NumericTraitPredictionAccuracyInfoMap, error){
func DecodeBytesToNumericAttributePredictionAccuracyInfoMap(inputBytes []byte)(NumericAttributePredictionAccuracyInfoMap, error){
if (inputBytes == nil){
return nil, errors.New("DecodeBytesToNumericTraitPredictionAccuracyInfoMap called with nil inputBytes.")
return nil, errors.New("DecodeBytesToNumericAttributePredictionAccuracyInfoMap called with nil inputBytes.")
}
buffer := bytes.NewBuffer(inputBytes)
decoder := gob.NewDecoder(buffer)
var newNumericTraitPredictionAccuracyInfoMap NumericTraitPredictionAccuracyInfoMap
var newNumericAttributePredictionAccuracyInfoMap NumericAttributePredictionAccuracyInfoMap
err := decoder.Decode(&newNumericTraitPredictionAccuracyInfoMap)
err := decoder.Decode(&newNumericAttributePredictionAccuracyInfoMap)
if (err != nil){ return nil, err }
return newNumericTraitPredictionAccuracyInfoMap, nil
return newNumericAttributePredictionAccuracyInfoMap, nil
}
//Outputs:
@ -471,48 +472,37 @@ func GetNeuralNetworkDiscreteTraitPredictionFromGenomeMap(traitName string, geno
return true, true, predictedOutcomeName, predictionAccuracy, quantityOfLociKnown, quantityOfPhasedLoci, nil
}
// This function is used to predict numeric traits and polygenic disease risk scores
//Outputs:
// -bool: Neural network model exists for this trait (trait prediction is possible for this trait)
// -bool: Trait prediction is possible for this user (User has at least 1 known trait locus value)
// -float64: Predicted trait outcome (Example: Height in centimeters)
// -bool: Neural network model exists for this attribute (neural network prediction is possible for this attribute)
// -bool: Attribute prediction is possible for this user (User has at least 1 known attribute locus value)
// -float64: Predicted attribute outcome (Example: Height in centimeters)
// -map[int]float64: Accuracy ranges map
// -Map Structure: Probability prediction is accurate (X) -> Distance from prediction that must be travelled in both directions to
// create a range in which the true value will fall into, X% of the time
// -int: Quantity of loci known
// -int: Quantity of phased loci
// -error
func GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName string, genomeMap map[int64]locusValue.LocusValue)(bool, bool, float64, map[int]float64, int, int, error){
func GetNeuralNetworkNumericAttributePredictionFromGenomeMap(attributeName string, attributeLociList []int64, genomeMap map[int64]locusValue.LocusValue)(bool, bool, float64, map[int]float64, int, int, error){
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil) { return false, false, 0, nil, 0, 0, err }
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Numeric"){
return false, false, 0, nil, 0, 0, errors.New("GetNeuralNetworkNumericTraitPredictionFromGenomeMap called with non-discrete trait: " + traitName)
}
// This is a map of rsIDs which influence this trait
traitRSIDsList := traitObject.LociList
if (len(traitRSIDsList) == 0){
// Prediction is not possible for this trait
return false, false, 0, nil, 0, 0, nil
}
predictionModelExists, predictionModelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
predictionModelExists, predictionModelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(attributeName)
if (predictionModelExists == false){
// Prediction is not possible for this trait
// Prediction is not possible for this attribute
return false, false, 0, nil, 0, 0, nil
}
traitRSIDsListCopy := slices.Clone(traitRSIDsList)
slices.Sort(traitRSIDsListCopy)
if (len(attributeLociList) == 0){
return false, false, 0, nil, 0, 0, errors.New("GetNeuralNetworkNumericAttributePredictionFromGenomeMap called with empty attributeLociList for attribute with an existing neural network.")
}
neuralNetworkInput, quantityOfLociKnown, quantityOfPhasedLoci, err := createInputNeuralNetworkLayerFromGenomeMap(traitRSIDsListCopy, genomeMap)
attributeLociListCopy := slices.Clone(attributeLociList)
slices.Sort(attributeLociListCopy)
neuralNetworkInput, quantityOfLociKnown, quantityOfPhasedLoci, err := createInputNeuralNetworkLayerFromGenomeMap(attributeLociListCopy, genomeMap)
if (err != nil) { return false, false, 0, nil, 0, 0, err }
if (quantityOfLociKnown == 0){
// We can't predict anything about this trait for this genome
// We can't predict anything about this attribute for this genome
return true, false, 0, nil, 0, 0, nil
}
@ -522,25 +512,25 @@ func GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName string, genom
outputLayer, err := GetNeuralNetworkRawPrediction(&neuralNetworkObject, true, neuralNetworkInput)
if (err != nil) { return false, false, 0, nil, 0, 0, err }
predictedOutcomeValue, err := GetNumericOutcomeValueFromOutputLayer(traitName, outputLayer)
predictedOutcomeValue, err := GetNumericOutcomeValueFromOutputLayer(attributeName, outputLayer)
if (err != nil) { return false, false, 0, nil, 0, 0, err }
modelTraitAccuracyInfoFile, err := geneticPredictionModels.GetPredictionModelNumericTraitAccuracyInfoBytes(traitName)
modelAccuracyInfoFile, err := geneticPredictionModels.GetPredictionModelNumericAttributeAccuracyInfoBytes(attributeName)
if (err != nil) { return false, false, 0, nil, 0, 0, err }
modelTraitAccuracyInfoMap, err := DecodeBytesToNumericTraitPredictionAccuracyInfoMap(modelTraitAccuracyInfoFile)
modelAccuracyInfoMap, err := DecodeBytesToNumericAttributePredictionAccuracyInfoMap(modelAccuracyInfoFile)
if (err != nil) { return false, false, 0, nil, 0, 0, err }
// We create a prediction confidence ranges map for our prediction
getPredictionConfidenceRangesMap := func()map[int]float64{
totalNumberOfTraitLoci := len(traitRSIDsList)
totalNumberOfAttributeLoci := len(attributeLociListCopy)
proportionOfLociTested := float64(quantityOfLociKnown)/float64(totalNumberOfTraitLoci)
proportionOfLociTested := float64(quantityOfLociKnown)/float64(totalNumberOfAttributeLoci)
percentageOfLociTested := int(proportionOfLociTested * 100)
proportionOfPhasedLoci := float64(quantityOfPhasedLoci)/float64(totalNumberOfTraitLoci)
proportionOfPhasedLoci := float64(quantityOfPhasedLoci)/float64(totalNumberOfAttributeLoci)
percentageOfPhasedLoci := int(proportionOfPhasedLoci * 100)
// This is a value between 0 and 100 that represents the most similar confidence ranges map for this prediction
@ -552,10 +542,10 @@ func GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName string, genom
// Y = Number of phased loci
closestPredictionConfidenceRangesMapDistance := float64(0)
for traitOutcomeInfo, traitPredictionConfidenceRangesMap := range modelTraitAccuracyInfoMap{
for attributeOutcomeInfo, attributePredictionConfidenceRangesMap := range modelAccuracyInfoMap{
currentPercentageOfLociTested := traitOutcomeInfo.PercentageOfLociTested
currentPercentageOfPhasedLoci := traitOutcomeInfo.PercentageOfPhasedLoci
currentPercentageOfLociTested := attributeOutcomeInfo.PercentageOfLociTested
currentPercentageOfPhasedLoci := attributeOutcomeInfo.PercentageOfPhasedLoci
// Distance Formula for 2 coordinates (x1, y1) and (x2, y2):
// distance = √((x2 - x1)^2 + (y2 - y1)^2)
@ -567,12 +557,12 @@ func GetNeuralNetworkNumericTraitPredictionFromGenomeMap(traitName string, genom
if (distance == 0){
// We found the exact prediction confidence ranges map
return traitPredictionConfidenceRangesMap
return attributePredictionConfidenceRangesMap
}
if (closestPredictionConfidenceRangesMap == nil || distance < closestPredictionConfidenceRangesMapDistance){
closestPredictionConfidenceRangesMapDistance = distance
closestPredictionConfidenceRangesMap = traitPredictionConfidenceRangesMap
closestPredictionConfidenceRangesMap = attributePredictionConfidenceRangesMap
}
}
@ -789,11 +779,11 @@ func GetDiscreteOutcomeNameFromOutputLayer(traitName string, verifyOutputLayer b
// This function returns which outcome is being described from a neural network's final output layer
// This is only used for discrete traits
// This is only used for numeric traits and polygenic diseases
// Outputs:
// -float64: Output Value (example: 150 centimeters)
// -error
func GetNumericOutcomeValueFromOutputLayer(traitName string, outputLayer []float32)(float64, error){
func GetNumericOutcomeValueFromOutputLayer(attributeName string, outputLayer []float32)(float64, error){
if (len(outputLayer) != 1){
return 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with output layer which is not length of 1")
@ -807,15 +797,19 @@ func GetNumericOutcomeValueFromOutputLayer(traitName string, outputLayer []float
getOutcomeMinAndMax := func()(float64, float64, error){
switch traitName{
switch attributeName{
case "Height":{
// Shortest person of all time: 54 cm
// Tallest person of all time: 272 cm
return 54, 272, nil
}
case "Autism",
"Homosexualness":{
return 0, 10, nil
}
}
return 0, 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with unknown traitName: " + traitName)
return 0, 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with unknown attributeName: " + attributeName)
}
outcomeMin, outcomeMax, err := getOutcomeMinAndMax()
@ -833,9 +827,9 @@ func GetNumericOutcomeValueFromOutputLayer(traitName string, outputLayer []float
// -int: Layer 3 neuron count
// -int: Layer 4 neuron count (output layer)
// -error
func getNeuralNetworkLayerSizes(traitName string)(int, int, int, int, error){
func getNeuralNetworkLayerSizes(attributeName string)(int, int, int, int, error){
switch traitName{
switch attributeName{
case "Eye Color":{
@ -856,9 +850,19 @@ func getNeuralNetworkLayerSizes(traitName string)(int, int, int, int, error){
// There is 1 output neuron, representing a height value
return 3000, 3, 2, 1, nil
}
case "Autism":{
// There are 1428 input neurons
// There is 1 output neuron, representing an autism value
return 1428, 3, 2, 1, nil
}
case "Homosexualness":{
// There are 12 input neurons
// There is 1 output neuron, representing a homosexualness value
return 12, 10, 5, 1, nil
}
}
return 0, 0, 0, 0, errors.New("getNeuralNetworkLayerSizes called with unknown traitName: " + traitName)
return 0, 0, 0, 0, errors.New("getNeuralNetworkLayerSizes called with unknown attributeName: " + attributeName)
}
//This function converts a genome allele to a neuron to use in a tensor
@ -903,22 +907,50 @@ func convertAlleleToNeuron(allele string)(float32, error){
// -[]TrainingData: List of TrainingData for the user which we will use to train the model
// -error
func CreateGeneticPredictionTrainingData_OpenSNP(
traitName string,
attributeName string,
userPhenotypeDataObject readBiobankData.PhenotypeData_OpenSNP,
userLocusValuesMap map[int64]locusValue.LocusValue)(bool, []TrainingData, error){
if (traitName != "Eye Color" && traitName != "Lactose Tolerance" && traitName != "Height"){
return false, nil, errors.New("CreateGeneticPredictionTrainingData_OpenSNP called with unknown traitName: " + traitName)
}
//Outputs:
// -[]int64: Attribute rsIDs list
// -error
getAttributeLociList := func()([]int64, error){
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil) { return false, nil, err }
switch attributeName{
case "Eye Color",
"Lactose Tolerance",
"Height",
"Homosexualness":{
traitObject, err := traits.GetTraitObject(attributeName)
if (err != nil) { return nil, err }
// This is a list of rsIDs which influence this trait
traitRSIDsList := traitObject.LociList
traitLociList := traitObject.LociList
if (len(traitRSIDsList) == 0){
return false, nil, errors.New("traitObject contains no rsIDs.")
return traitLociList, nil
}
case "Autism":{
diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(attributeName)
if (err != nil) { return nil, err }
// This is a list of rsIDs which influence this disease
diseaseLociList := diseaseObject.LociList
return diseaseLociList, nil
}
}
return nil, errors.New("CreateGeneticPredictionTrainingData_OpenSNP called with unknown attributeName: " + attributeName)
}
attributeLociList, err := getAttributeLociList()
if (err != nil) { return false, nil, err }
if (len(attributeLociList) == 0){
return false, nil, errors.New("getAttributeLociList returning empty attributeLociList.")
}
// Each layer is represented as a []float32
@ -927,7 +959,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
// Each TrainingData holds a variation of the user's genome rsID values
// We add many rows with withheld data to improve training data
numberOfInputLayerRows, _, _, numberOfOutputLayerRows, err := getNeuralNetworkLayerSizes(traitName)
numberOfInputLayerRows, _, _, numberOfOutputLayerRows, err := getNeuralNetworkLayerSizes(attributeName)
if (err != nil) { return false, nil, err }
// Each rsID is represented by 3 neurons: LocusExists/LocusIsPhased, Allele1 Value, Allele2 Value
@ -935,7 +967,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
// -0 = Locus value is unknown
// -0.5 = Locus Is known, phase is unknown
// -1 = Locus Is Known, phase is known
expectedNumberOfInputLayerRows := len(traitRSIDsList) * 3
expectedNumberOfInputLayerRows := len(attributeLociList) * 3
if (numberOfInputLayerRows != expectedNumberOfInputLayerRows){
@ -944,9 +976,9 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
return false, nil, errors.New("numberOfInputLayerRows is not expected: " + expectedNumberOfInputLayerRowsString)
}
checkIfAnyTraitLocusValuesExist := func()bool{
checkIfAnyAttributeLocusValuesExist := func()bool{
for _, rsID := range traitRSIDsList{
for _, rsID := range attributeLociList{
_, exists := userLocusValuesMap[rsID]
if (exists == true){
@ -957,29 +989,29 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
return false
}
anyTraitLocusValuesExist := checkIfAnyTraitLocusValuesExist()
if (anyTraitLocusValuesExist == false){
// The user's genome does not contain any of this trait's locus values
anyAttributeLocusValuesExist := checkIfAnyAttributeLocusValuesExist()
if (anyAttributeLocusValuesExist == false){
// The user's genome does not contain any of this attribute's locus values
// We will not train on their data
return false, nil, nil
}
// We sort rsIDs in ascending order
traitRSIDsListCopy := slices.Clone(traitRSIDsList)
slices.Sort(traitRSIDsListCopy)
attributeLociListCopy := slices.Clone(attributeLociList)
slices.Sort(attributeLociListCopy)
// This function returns the outputLayer for all trainingDatas for this user
// Each outputLayer represents the user's trait value (Example: "Blue" for Eye Color)
// Each outputLayer represents the user's attribute value (Example: "Blue" for Eye Color)
// Each outputLayer is identical, because each TrainingData example belongs to the same user
//
// Outputs:
// -bool: User trait value is known
// -bool: User attribute value is known
// -[]float32: Neuron values for layer
// -error
getUserTraitValueNeurons := func()(bool, []float32, error){
getUserAttributeValueNeurons := func()(bool, []float32, error){
switch traitName{
switch attributeName{
case "Eye Color":{
@ -1046,21 +1078,51 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
return true, outputLayer, nil
}
}
case "Autism":{
return false, nil, errors.New("Unknown traitName: " + traitName)
}
userTraitValueExists, userTraitValueNeurons, err := getUserTraitValueNeurons()
if (err != nil) { return false, nil, err }
if (userTraitValueExists == false){
// User cannot be used to train the model.
// They do not have a value for this trait.
userAutismIsKnown := userPhenotypeDataObject.AutismIsKnown
if (userAutismIsKnown == false){
return false, nil, nil
}
if (len(userTraitValueNeurons) != numberOfOutputLayerRows){
return false, nil, errors.New("getUserTraitValueNeurons returning invalid length layer slice.")
userAutism := userPhenotypeDataObject.Autism
outputValueFloat32 := float32(userAutism)
outputLayer := []float32{outputValueFloat32}
return true, outputLayer, nil
}
case "Homosexualness":{
userHomosexualnessIsKnown := userPhenotypeDataObject.HomosexualnessIsKnown
if (userHomosexualnessIsKnown == false){
return false, nil, nil
}
userHomosexualness := userPhenotypeDataObject.Homosexualness
outputValueFloat32 := float32(userHomosexualness)
outputLayer := []float32{outputValueFloat32}
return true, outputLayer, nil
}
}
return false, nil, errors.New("Unknown attributeName: " + attributeName)
}
userAttributeValueExists, userAttributeValueNeurons, err := getUserAttributeValueNeurons()
if (err != nil) { return false, nil, err }
if (userAttributeValueExists == false){
// User cannot be used to train the model.
// They do not have a value for this attribute.
return false, nil, nil
}
if (len(userAttributeValueNeurons) != numberOfOutputLayerRows){
return false, nil, errors.New("getUserAttributeValueNeurons returning invalid length layer slice.")
}
// We want the initial training data to be the same for each call of this function that has the same input parameters
@ -1134,11 +1196,11 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
anyLocusExists := false
inputLayerLength := len(traitRSIDsListCopy) * 3
inputLayerLength := len(attributeLociListCopy) * 3
inputLayer := make([]float32, 0, inputLayerLength)
for _, rsID := range traitRSIDsListCopy{
for _, rsID := range attributeLociListCopy{
randomFloat := pseudorandomNumberGenerator.Float64()
if (randomFloat > probabilityOfUsingLoci){
@ -1209,11 +1271,11 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
continue
}
userTraitValueNeuronsCopy := slices.Clone(userTraitValueNeurons)
userAttributeValueNeuronsCopy := slices.Clone(userAttributeValueNeurons)
newTrainingData := TrainingData{
InputLayer: inputLayer,
OutputLayer: userTraitValueNeuronsCopy,
OutputLayer: userAttributeValueNeuronsCopy,
}
trainingDataList = append(trainingDataList, newTrainingData)
@ -1222,9 +1284,9 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
return true, trainingDataList, nil
}
func GetNewUntrainedNeuralNetworkObject(traitName string)(*NeuralNetwork, error){
func GetNewUntrainedNeuralNetworkObject(attributeName string)(*NeuralNetwork, error){
layer1NeuronCount, layer2NeuronCount, layer3NeuronCount, layer4NeuronCount, err := getNeuralNetworkLayerSizes(traitName)
layer1NeuronCount, layer2NeuronCount, layer3NeuronCount, layer4NeuronCount, err := getNeuralNetworkLayerSizes(attributeName)
if (err != nil) { return nil, err }
// This is the graph object we add each layer to
@ -1304,10 +1366,10 @@ func (inputNetwork *NeuralNetwork)getLearnables()gorgonia.Nodes{
// This function will train the neural network
// The function is passed a batch of TrainingData examples to train on
// Inputs:
// -string: Trait Name
// -bool: Trait is Numeric
// -An example of a numeric trait is Height
// -An example of a discrete trait is Eye Color, which has discrete outcomes (colors)
// -string: Attribute Name
// -bool: Attribute is Numeric
// -An example of a numeric attribute is Height
// -An example of a discrete attribute is Eye Color, which has discrete outcomes (colors)
// -*NeuralNetwork
// -func()(bool, bool, TrainingData, error): Function to get the next training data.
// -Outputs:
@ -1318,9 +1380,9 @@ func (inputNetwork *NeuralNetwork)getLearnables()gorgonia.Nodes{
// Outputs:
// -bool: Process completed (was not stopped mid-way)
// -error
func TrainNeuralNetwork(traitName string, traitIsNumeric bool, neuralNetworkObject *NeuralNetwork, getNextTrainingData func()(bool, bool, TrainingData, error))(bool, error){
func TrainNeuralNetwork(attributeName string, attributeIsNumeric bool, neuralNetworkObject *NeuralNetwork, getNextTrainingData func()(bool, bool, TrainingData, error))(bool, error){
layer1NeuronCount, _, _, layer4NeuronCount, err := getNeuralNetworkLayerSizes(traitName)
layer1NeuronCount, _, _, layer4NeuronCount, err := getNeuralNetworkLayerSizes(attributeName)
if (err != nil) { return false, err }
neuralNetworkGraph := neuralNetworkObject.graph
@ -1340,7 +1402,7 @@ func TrainNeuralNetwork(traitName string, traitIsNumeric bool, neuralNetworkObje
gorgonia.WithShape(1, layer4NeuronCount),
)
err = neuralNetworkObject.buildNeuralNetwork(trainingDataInputNode, traitIsNumeric)
err = neuralNetworkObject.buildNeuralNetwork(trainingDataInputNode, attributeIsNumeric)
if (err != nil) { return false, err }
// This computes the loss (how accurate was our prediction)
@ -1431,7 +1493,7 @@ func TrainNeuralNetwork(traitName string, traitIsNumeric bool, neuralNetworkObje
// Outputs:
// -[]float32: Output neurons
// -error
func GetNeuralNetworkRawPrediction(inputNeuralNetwork *NeuralNetwork, traitIsNumeric bool, inputLayer []float32)([]float32, error){
func GetNeuralNetworkRawPrediction(inputNeuralNetwork *NeuralNetwork, attributeIsNumeric bool, inputLayer []float32)([]float32, error){
neuralNetworkGraph := inputNeuralNetwork.graph
@ -1455,7 +1517,7 @@ func GetNeuralNetworkRawPrediction(inputNeuralNetwork *NeuralNetwork, traitIsNum
if (err != nil) { return nil, err }
err = inputNeuralNetwork.buildNeuralNetwork(inputNode, traitIsNumeric)
err = inputNeuralNetwork.buildNeuralNetwork(inputNode, attributeIsNumeric)
if (err != nil){ return nil, err }
// Now we create a virtual machine to compute the prediction
@ -1479,7 +1541,7 @@ func GetNeuralNetworkRawPrediction(inputNeuralNetwork *NeuralNetwork, traitIsNum
// This function will take a neural network and input layer and build the network to be able to compute a prediction
// We need to run a virtual machine after calling this function in order for the prediction to be generated
func (inputNetwork *NeuralNetwork)buildNeuralNetwork(inputLayer *gorgonia.Node, traitIsNumeric bool)error{
func (inputNetwork *NeuralNetwork)buildNeuralNetwork(inputLayer *gorgonia.Node, predictionIsNumeric bool)error{
// We copy node pointer (says to do this in a resource i'm reading)
@ -1518,7 +1580,7 @@ func (inputNetwork *NeuralNetwork)buildNeuralNetwork(inputLayer *gorgonia.Node,
return errors.New("Layer 3 multiplication failed: " + err.Error())
}
if (traitIsNumeric == false){
if (predictionIsNumeric == false){
// We SoftMax the output to get the prediction

View file

@ -483,193 +483,74 @@ func GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisOb
return true, probabilityOf0MutationsLowerBound, probabilityOf0MutationsUpperBound, probabilityOf0MutationsFormatted, probabilityOf1MutationLowerBound, probabilityOf1MutationUpperBound, probabilityOf1MutationFormatted, probabilityOf2MutationsLowerBound, probabilityOf2MutationsUpperBound, probabilityOf2MutationsFormatted, nil
}
//Outputs:
// -bool: Polygenic Disease Risk Score known (any loci values exist)
// -int: Person Disease risk score
// -string: Person Disease risk score formatted (has "/10" suffix)
// -int: Quantity of loci tested
// -bool: Conflict exists
// -bool: Any analysis exists
// -int: Predicted risk score (0-10)
// -map[int]float64: Prediction confidence ranges map
// -Map Structure: Percentage probability of accurate prediction -> distance of range in both directions from prediction
// -int: Quantity of loci known
// -int: Quantity of phased loci
// -bool: Conflict exists (between any of these results for each genome)
// -error
func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte)(bool, int, string, int, bool, error){
func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte)(bool, int, map[int]float64, int, int, bool, error){
personPolygenicDiseasesMap := personAnalysisObject.PolygenicDiseasesMap
personPolygenicDiseaseInfo, exists := personPolygenicDiseasesMap[diseaseName]
personDiseaseInfoObject, exists := personPolygenicDiseasesMap[diseaseName]
if (exists == false){
return false, 0, "", 0, false, nil
return false, 0, nil, 0, 0, false, nil
}
personPolygenicDiseaseInfoMap := personPolygenicDiseaseInfo.PolygenicDiseaseInfoMap
personDiseaseInfoMap := personDiseaseInfoObject.PolygenicDiseaseInfoMap
conflictExists := personDiseaseInfoObject.ConflictExists
genomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier]
personGenomeDiseaseInfoObject, exists := personDiseaseInfoMap[genomeIdentifier]
if (exists == false){
return false, 0, "", 0, false, nil
return false, 0, nil, 0, 0, false, nil
}
conflictExists := personPolygenicDiseaseInfo.ConflictExists
predictedRiskScore := personGenomeDiseaseInfoObject.RiskScore
confidenceRangesMap := personGenomeDiseaseInfoObject.ConfidenceRangesMap
quantityOfLociKnown := personGenomeDiseaseInfoObject.QuantityOfLociKnown
quantityOfPhasedLoci := personGenomeDiseaseInfoObject.QuantityOfPhasedLoci
personDiseaseRiskScore := genomePolygenicDiseaseInfo.RiskScore
personDiseaseRiskScoreString := helpers.ConvertIntToString(personDiseaseRiskScore)
personDiseaseRiskScoreFormatted := personDiseaseRiskScoreString + "/10"
quantityOfLociTested := genomePolygenicDiseaseInfo.QuantityOfLociTested
return true, personDiseaseRiskScore, personDiseaseRiskScoreFormatted, quantityOfLociTested, conflictExists, nil
return true, predictedRiskScore, confidenceRangesMap, quantityOfLociKnown, quantityOfPhasedLoci, conflictExists, nil
}
//Outputs:
// -bool: Offspring Disease Risk Score known
// -int: Offspring average disease risk score
// -string: Offspring Disease average risk score formatted (has "/10" suffix)
// -[]int: Sample Offspring Risk Scores List
// -int: Quantity of loci tested
// -bool: Conflict exists
// -bool: Analysis exists
// -int: Average offspring risk score (0-10)
// -map[int]float64: Prediction confidence ranges map
// -int: Quantity of loci known
// -int: Quantity of Parental phased loci
// -[]int: 100 Sample offspring risk scores
// -bool: Conflict exists (Between this genome pair and other genome pairs)
// -error
func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte)(bool, int, string, []int, int, bool, error){
func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte)(bool, int, map[int]float64, int, int, []int, bool, error){
couplePolygenicDiseasesMap := coupleAnalysisObject.PolygenicDiseasesMap
offspringDiseasesMap := coupleAnalysisObject.PolygenicDiseasesMap
couplePolygenicDiseaseInfo, exists := couplePolygenicDiseasesMap[diseaseName]
diseaseInfoObject, exists := offspringDiseasesMap[diseaseName]
if (exists == false){
return false, 0, "", nil, 0, false, nil
return false, 0, nil, 0, 0, nil, false, nil
}
polygenicDiseaseInfoMap := couplePolygenicDiseaseInfo.PolygenicDiseaseInfoMap
diseaseInfoMap := diseaseInfoObject.PolygenicDiseaseInfoMap
conflictExists := diseaseInfoObject.ConflictExists
genomePairPolygenicDiseaseInfo, exists := polygenicDiseaseInfoMap[genomePairIdentifier]
genomePairDiseaseInfoObject, exists := diseaseInfoMap[genomePairIdentifier]
if (exists == false){
return false, 0, "", nil, 0, false, nil
return false, 0, nil, 0, 0, nil, false, nil
}
conflictExists := couplePolygenicDiseaseInfo.ConflictExists
offspringAverageRiskScore := genomePairDiseaseInfoObject.OffspringAverageRiskScore
predictionConfidenceRangesMap := genomePairDiseaseInfoObject.PredictionConfidenceRangesMap
quantityOfLociKnown := genomePairDiseaseInfoObject.QuantityOfLociKnown
quantityOfParentalPhasedLoci := genomePairDiseaseInfoObject.QuantityOfParentalPhasedLoci
sampleOffspringRiskScoresList := genomePairDiseaseInfoObject.SampleOffspringRiskScoresList
quantityOfLociTested := genomePairPolygenicDiseaseInfo.QuantityOfLociTested
offspringAverageRiskScore := genomePairPolygenicDiseaseInfo.OffspringAverageRiskScore
offspringAverageRiskScoreString := helpers.ConvertIntToString(offspringAverageRiskScore)
offspringAverageRiskScoreFormatted := offspringAverageRiskScoreString + "/10"
sampleOffspringRiskScoresList := genomePairPolygenicDiseaseInfo.SampleOffspringRiskScoresList
return true, offspringAverageRiskScore, offspringAverageRiskScoreFormatted, sampleOffspringRiskScoresList, quantityOfLociTested, conflictExists, nil
}
//Outputs:
// -bool: Risk Weight and base pair known
// -int: Locus risk weight
// -bool: Locus odds ratio known
// -float64: Locus odds ratio
// -string: Locus odds ratio formatted (with x suffix)
// -error
func GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalyisObject geneticAnalysis.PersonAnalysis, diseaseName string, locusIdentifier [3]byte, genomeIdentifier [16]byte)(bool, int, bool, float64, string, error){
personPolygenicDiseasesMap := personAnalyisObject.PolygenicDiseasesMap
personPolygenicDiseaseMap, exists := personPolygenicDiseasesMap[diseaseName]
if (exists == false){
return false, 0, false, 0, "", nil
}
personPolygenicDiseaseInfoMap := personPolygenicDiseaseMap.PolygenicDiseaseInfoMap
personGenomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier]
if (exists == false){
return false, 0, false, 0, "", nil
}
genomeLociInfoMap := personGenomePolygenicDiseaseInfo.LociInfoMap
locusInfoObject, exists := genomeLociInfoMap[locusIdentifier]
if (exists == false){
return false, 0, false, 0, "", nil
}
locusRiskWeight := locusInfoObject.RiskWeight
locusOddsRatioIsKnown := locusInfoObject.OddsRatioIsKnown
if (locusOddsRatioIsKnown == false){
return true, locusRiskWeight, false, 0, "", nil
}
locusOddsRatio := locusInfoObject.OddsRatio
genomeLocusOddsRatioString := helpers.ConvertFloat64ToStringRounded(locusOddsRatio, 2)
locusOddsRatioFormatted := genomeLocusOddsRatioString + "x"
return true, locusRiskWeight, true, locusOddsRatio, locusOddsRatioFormatted, nil
}
//Outputs:
// -bool: Offspring risk weight known
// -int: Offspring risk weight
// -bool: Offspring odds ratio known
// -float64: Offspring odds ratio
// -string: Offspring odds ratio formatted (with + and < from unknownFactors weight sum and x suffix)
// -error
func GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, locusIdentifier [3]byte, genomePairIdentifier [32]byte)(bool, int, bool, float64, string, error){
offspringPolygenicDiseasesMap := coupleAnalysisObject.PolygenicDiseasesMap
offspringPolygenicDiseaseInfo, exists := offspringPolygenicDiseasesMap[diseaseName]
if (exists == false){
return false, 0, false, 0, "", nil
}
offspringPolygenicDiseaseMap := offspringPolygenicDiseaseInfo.PolygenicDiseaseInfoMap
genomePairPolygenicDiseaseInfo, exists := offspringPolygenicDiseaseMap[genomePairIdentifier]
if (exists == false){
return false, 0, false, 0, "", nil
}
genomePairLociInfoMap := genomePairPolygenicDiseaseInfo.LociInfoMap
locusInfoObject, exists := genomePairLociInfoMap[locusIdentifier]
if (exists == false){
return false, 0, false, 0, "", nil
}
offspringAverageRiskWeight := locusInfoObject.OffspringAverageRiskWeight
offspringOddsRatioIsKnown := locusInfoObject.OffspringOddsRatioIsKnown
if (offspringOddsRatioIsKnown == false){
return true, offspringAverageRiskWeight, false, 0, "", nil
}
offspringAverageOddsRatio := locusInfoObject.OffspringAverageOddsRatio
getOddsRatioFormatted := func()string{
offspringAverageUnknownOddsRatiosWeightSum := locusInfoObject.OffspringAverageUnknownOddsRatiosWeightSum
offspringAverageOddsRatioString := helpers.ConvertFloat64ToStringRounded(offspringAverageOddsRatio, 2)
if (offspringAverageUnknownOddsRatiosWeightSum == 0){
result := offspringAverageOddsRatioString + "x"
return result
}
if (offspringAverageUnknownOddsRatiosWeightSum < 0){
result := "<" + offspringAverageOddsRatioString + "x"
return result
}
// offspringAverageUnknownOddsRatiosWeightSum > 0
result := offspringAverageOddsRatioString + "x+"
return result
}
oddsRatioFormatted := getOddsRatioFormatted()
return true, offspringAverageRiskWeight, true, offspringAverageOddsRatio, oddsRatioFormatted, nil
return true, offspringAverageRiskScore, predictionConfidenceRangesMap, quantityOfLociKnown, quantityOfParentalPhasedLoci, sampleOffspringRiskScoresList, conflictExists, nil
}
//Outputs:
@ -892,7 +773,6 @@ func GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject g
}
//Outputs:
// -bool: Any analysis exists
// -float64: Predicted outcome (Example: Height in centimeters)
@ -964,6 +844,8 @@ func GetOffspringNumericTraitInfoFromGeneticAnalysis(coupleAnalysisObject geneti
return true, offspringAverageOutcome, predictionConfidenceRangesMap, quantityOfLociKnown, quantityOfParentalPhasedLoci, sampleOffspringOutcomesList, conflictExists, nil
}
// We use this function to verify a person genetic analysis is well formed
//TODO: Perform sanity checks on data
func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis)error{
@ -1015,25 +897,9 @@ func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnal
for _, genomeIdentifier := range allGenomeIdentifiersList{
_, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, genomeIdentifier)
_, _, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, genomeIdentifier)
if (err != nil) { return err }
}
diseaseLocusObjectsList := diseaseObject.LociList
for _, diseaseLocusObject := range diseaseLocusObjectsList{
locusIdentifierHex := diseaseLocusObject.LocusIdentifier
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
if (err != nil) { return err }
for _, genomeIdentifier := range allGenomeIdentifiersList{
_, _, _, _, _, err := GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
if (err != nil) { return err }
}
}
}
traitObjectsList, err := traits.GetTraitObjectsList()
@ -1138,25 +1004,9 @@ func VerifyCoupleGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnal
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
_, _, _, _, _, _, err := GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
_, _, _, _, _, _, _, err := GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
if (err != nil) { return err }
}
diseaseLocusObjectsList := diseaseObject.LociList
for _, diseaseLocusObject := range diseaseLocusObjectsList{
locusIdentifierHex := diseaseLocusObject.LocusIdentifier
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
if (err != nil) { return err }
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
_, _, _, _, _, err := GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, locusIdentifier, genomePairIdentifier)
if (err != nil) { return err }
}
}
}
traitObjectsList, err := traits.GetTraitObjectsList()

View file

@ -49,6 +49,29 @@ func ConvertCentimetersToFeetInchesTranslatedString(centimeters float64)(string,
return "", errors.New("ConvertCentimetersToFeetInchesTranslatedString called with invalid centimeters.")
}
getInchUnits := func()string{
if (inputInches == 1){
result := translation.TranslateTextFromEnglishToMyLanguage("inch")
return result
}
inchesTranslated := translation.TranslateTextFromEnglishToMyLanguage("inches")
return inchesTranslated
}
inchUnits := getInchUnits()
inputInchesString := ConvertFloat64ToStringRounded(inputInches, 1)
if (inputFeet == 0){
formattedResult := inputInchesString + " " + inchUnits
return formattedResult, nil
}
getFeetUnits := func()string{
if (inputFeet <= 1){
@ -64,22 +87,7 @@ func ConvertCentimetersToFeetInchesTranslatedString(centimeters float64)(string,
feetUnits := getFeetUnits()
getInchUnits := func()string{
if (inputInches == 1){
result := translation.TranslateTextFromEnglishToMyLanguage("inch")
return result
}
inchesTranslated := translation.TranslateTextFromEnglishToMyLanguage("inches")
return inchesTranslated
}
inchUnits := getInchUnits()
inputFeetString := ConvertIntToString(inputFeet)
inputInchesString := ConvertFloat64ToStringRounded(inputInches, 1)
formattedResult := inputFeetString + " " + feetUnits + ", " + inputInchesString + " " + inchUnits

View file

@ -684,9 +684,7 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
diseaseLociList := diseaseObject.LociList
for _, locusObject := range diseaseLociList{
locusRSID := locusObject.LocusRSID
for _, locusRSID := range diseaseLociList{
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
@ -723,9 +721,9 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
userDiseaseLocusValuesMap[locusRSID] = userLocusValueObject
}
anyLocusTested, userDiseaseRiskScore, _, _, err := createPersonGeneticAnalysis.GetPersonGenomePolygenicDiseaseInfo(diseaseLociList, userDiseaseLocusValuesMap, true)
neuralNetworkExists, anyLocusTested, userDiseaseRiskScore, _, _, _, err := createPersonGeneticAnalysis.GetPersonGenomePolygenicDiseaseAnalysis(diseaseObject, userDiseaseLocusValuesMap, true)
if (err != nil) { return false, 0, "", err }
if (anyLocusTested == false){
if (neuralNetworkExists == false || anyLocusTested == false){
continue
}
@ -803,9 +801,7 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
// Map Structure: rsID -> Locus Value
userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue)
for _, locusObject := range diseaseLociList{
locusRSID := locusObject.LocusRSID
for _, locusRSID := range diseaseLociList{
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
@ -842,9 +838,9 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
userDiseaseLocusValuesMap[locusRSID] = newLocusValueObject
}
anyLocusValuesTested, offspringAverageRiskScore, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo_Fast(diseaseLociList, myGenomeLocusValuesMap, userDiseaseLocusValuesMap)
neuralNetworkExists, anyLocusValuesTested, offspringAverageRiskScore, _, _, _, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseAnalysis(diseaseObject, myGenomeLocusValuesMap, userDiseaseLocusValuesMap)
if (err != nil) { return false, 0, "", err }
if (anyLocusValuesTested == false){
if (neuralNetworkExists == false || anyLocusValuesTested == false){
continue
}

View file

@ -214,11 +214,9 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
lociList := diseaseObject.LociList
for _, locusObject := range lociList{
for _, rsID := range lociList{
locusRSID := locusObject.LocusRSID
myLociToShareMap[locusRSID] = struct{}{}
myLociToShareMap[rsID] = struct{}{}
}
}

View file

@ -2267,11 +2267,9 @@ func initializeProfileAttributeObjectsList()error{
diseaseLociList := diseaseObject.LociList
for _, locusObject := range diseaseLociList{
for _, rsID := range diseaseLociList{
locusRSID := locusObject.LocusRSID
shareableRSIDsMap[locusRSID] = struct{}{}
shareableRSIDsMap[rsID] = struct{}{}
}
}

View file

@ -210,9 +210,7 @@ func TestProfileGeneticReferences(t *testing.T){
diseaseLociList := diseaseObject.LociList
for _, locusObject := range diseaseLociList{
locusRSID := locusObject.LocusRSID
for _, locusRSID := range diseaseLociList{
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)

View file

@ -21,6 +21,12 @@ var predictionModel_LactoseTolerance []byte
//go:embed predictionModels/HeightModel.gob
var predictionModel_Height []byte
//go:embed predictionModels/AutismModel.gob
var predictionModel_Autism []byte
//go:embed predictionModels/HomosexualnessModel.gob
var predictionModel_Homosexualness []byte
//Outputs:
// -bool: Model exists
@ -38,6 +44,12 @@ func GetGeneticPredictionModelBytes(traitName string)(bool, []byte){
case "Height":{
return true, predictionModel_Height
}
case "Autism":{
return true, predictionModel_Autism
}
case "Homosexualness":{
return true, predictionModel_Homosexualness
}
}
return false, nil
@ -65,19 +77,33 @@ func GetPredictionModelDiscreteTraitAccuracyInfoBytes(traitName string)([]byte,
return nil, errors.New("GetPredictionModelDiscreteTraitAccuracyInfoBytes called with unknown traitName: " + traitName)
}
//go:embed predictionModelAccuracies/HeightModelAccuracy.gob
var predictionAccuracy_Height []byte
// The files returned by this function are .gob encoded geneticPrediction.NumericTraitPredictionAccuracyInfoMap objects
func GetPredictionModelNumericTraitAccuracyInfoBytes(traitName string)([]byte, error){
//go:embed predictionModelAccuracies/AutismModelAccuracy.gob
var predictionAccuracy_Autism []byte
switch traitName{
//go:embed predictionModelAccuracies/HomosexualnessModelAccuracy.gob
var predictionAccuracy_Homosexualness []byte
// The files returned by this function are .gob encoded geneticPrediction.NumericAttributePredictionAccuracyInfoMap objects
func GetPredictionModelNumericAttributeAccuracyInfoBytes(attributeName string)([]byte, error){
switch attributeName{
case "Height":{
return predictionAccuracy_Height, nil
}
case "Autism":{
return predictionAccuracy_Autism, nil
}
case "Homosexualness":{
return predictionAccuracy_Homosexualness, nil
}
}
return nil, errors.New("GetPredictionModelNumericTraitAccuracyInfoBytes called with unknown traitName: " + traitName)
return nil, errors.New("GetPredictionModelNumericAttributeAccuracyInfoBytes called with unknown attributeName: " + attributeName)
}

View file

@ -9,13 +9,13 @@ import "seekia/internal/genetics/geneticPrediction"
func TestGeneticPredictionModels(t *testing.T){
traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"}
attributeNamesList := []string{"Eye Color", "Lactose Tolerance", "Height", "Autism"}
for _, traitName := range traitNamesList{
for _, attributeName := range attributeNamesList{
modelFound, modelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
modelFound, modelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(attributeName)
if (modelFound == false){
t.Fatalf("GetGeneticPredictionModelBytes failed to find model for trait: " + traitName)
t.Fatalf("GetGeneticPredictionModelBytes failed to find model for trait: " + attributeName)
}
_, err := geneticPrediction.DecodeBytesToNeuralNetworkObject(modelBytes)
@ -43,18 +43,18 @@ func TestGeneticPredictionModelAccuracies(t *testing.T){
}
}
numericTraitNamesList := []string{"Height"}
numericAttributeNamesList := []string{"Height", "Autism", "Homosexualness"}
for _, traitName := range numericTraitNamesList{
for _, attributeName := range numericAttributeNamesList{
accuracyInfoBytes, err := geneticPredictionModels.GetPredictionModelNumericTraitAccuracyInfoBytes(traitName)
accuracyInfoBytes, err := geneticPredictionModels.GetPredictionModelNumericAttributeAccuracyInfoBytes(attributeName)
if (err != nil){
t.Fatalf("GetPredictionModelNumericTraitAccuracyInfoBytes failed: " + err.Error())
t.Fatalf("GetPredictionModelNumericAttributeAccuracyInfoBytes failed: " + err.Error())
}
_, err = geneticPrediction.DecodeBytesToNumericTraitPredictionAccuracyInfoMap(accuracyInfoBytes)
_, err = geneticPrediction.DecodeBytesToNumericAttributePredictionAccuracyInfoMap(accuracyInfoBytes)
if (err != nil){
t.Fatalf("DecodeBytesToNumericTraitPredictionAccuracyInfoMap failed: " + err.Error())
t.Fatalf("DecodeBytesToNumericAttributePredictionAccuracyInfoMap failed: " + err.Error())
}
}
}

View file

@ -0,0 +1,8 @@
// attributeLoci provides loci associated with various bodily attributes
// For example, this package stores all loci associated with the brain
// We can then use this same set of loci to predict all attributes pertaining to the brain, such as autism, depression, anxiety, etc.
// We need this package because we can't have packages that import from polygenicDiseases->traits and traits->polygenicDiseases
package attributeLoci

View file

@ -0,0 +1,605 @@
package attributeLoci
import "maps"
// Outputs:
// -map[int64]map[string]string
// -Map Structure: rsID -> map[ReferenceName]ReferenceLink
func GetAutismLoci()map[int64]map[string]string{
// Map Structure: rsID -> (map[Reference Name]Reference Link)
locusReferencesMap := make(map[int64]map[string]string)
locus1_ReferencesMap := make(map[string]string)
locus1_ReferencesMap["SNPedia.com - rs10513025"] = "https://www.snpedia.com/index.php/Rs10513025"
locusReferencesMap[10513025] = locus1_ReferencesMap
locus2_ReferencesMap := make(map[string]string)
locus2_ReferencesMap["SNPedia.com - rs2710102"] = "https://www.snpedia.com/index.php/Rs2710102"
locusReferencesMap[2710102] = locus2_ReferencesMap
locus3_ReferencesMap := make(map[string]string)
locus3_ReferencesMap["SNPedia.com - rs7794745"] = "https://www.snpedia.com/index.php/Rs7794745"
locusReferencesMap[7794745] = locus3_ReferencesMap
locus4_ReferencesMap := make(map[string]string)
locus4_ReferencesMap["SNPedia.com - rs1858830"] = "https://www.snpedia.com/index.php/Rs1858830"
locusReferencesMap[1858830] = locus4_ReferencesMap
locus5_ReferencesMap := make(map[string]string)
locus5_ReferencesMap["SNPedia.com - rs1322784"] = "https://www.snpedia.com/index.php/Rs1322784"
locusReferencesMap[1322784] = locus5_ReferencesMap
locus6_ReferencesMap := make(map[string]string)
locus6_ReferencesMap["SNPedia.com - rs1804197"] = "https://www.snpedia.com/index.php/Rs1804197"
locusReferencesMap[1804197] = locus6_ReferencesMap
locus7_ReferencesMap := make(map[string]string)
locus7_ReferencesMap["SNPedia.com - rs265981"] = "https://www.snpedia.com/index.php/Rs265981"
locusReferencesMap[265981] = locus7_ReferencesMap
locus8_ReferencesMap := make(map[string]string)
locus8_ReferencesMap["SNPedia.com - rs4532"] = "https://www.snpedia.com/index.php/Rs4532"
locusReferencesMap[4532] = locus8_ReferencesMap
locus9_ReferencesMap := make(map[string]string)
locus9_ReferencesMap["SNPedia.com - rs686"] = "https://www.snpedia.com/index.php/Rs686"
locusReferencesMap[686] = locus9_ReferencesMap
locus10_ReferencesMap := make(map[string]string)
locus10_ReferencesMap["SNPedia.com - rs6766410"] = "https://www.snpedia.com/index.php/Rs6766410"
locusReferencesMap[6766410] = locus10_ReferencesMap
locus11_ReferencesMap := make(map[string]string)
locus11_ReferencesMap["SNPedia.com - rs6807362"] = "https://www.snpedia.com/index.php/Rs6807362"
locusReferencesMap[6807362] = locus11_ReferencesMap
locus12_ReferencesMap := make(map[string]string)
locus12_ReferencesMap["SNPedia.com - rs1143674"] = "https://www.snpedia.com/index.php/Rs1143674"
locusReferencesMap[1143674] = locus12_ReferencesMap
locus13_ReferencesMap := make(map[string]string)
locus13_ReferencesMap["SNPedia.com - rs2745557"] = "https://www.snpedia.com/index.php/Rs2745557"
locusReferencesMap[2745557] = locus13_ReferencesMap
locus14_ReferencesMap := make(map[string]string)
locus14_ReferencesMap["SNPedia.com - rs2217262"] = "https://www.snpedia.com/index.php/Rs2217262"
locusReferencesMap[2217262] = locus14_ReferencesMap
locus15_ReferencesMap := make(map[string]string)
locus15_ReferencesMap["SNPedia.com - rs373126732"] = "https://www.snpedia.com/index.php/Rs373126732"
locusReferencesMap[373126732] = locus15_ReferencesMap
locus16_ReferencesMap := make(map[string]string)
locus16_ReferencesMap["SNPedia.com - rs184718561"] = "https://www.snpedia.com/index.php/Rs184718561"
locusReferencesMap[184718561] = locus16_ReferencesMap
locus17_ReferencesMap := make(map[string]string)
locus17_ReferencesMap["SNPedia.com - rs1445442"] = "https://www.snpedia.com/index.php/Rs1445442"
locusReferencesMap[1445442] = locus17_ReferencesMap
locus18_ReferencesMap := make(map[string]string)
locus18_ReferencesMap["SNPedia.com - rs2421826"] = "https://www.snpedia.com/index.php/Rs2421826"
locusReferencesMap[2421826] = locus18_ReferencesMap
locus19_ReferencesMap := make(map[string]string)
locus19_ReferencesMap["SNPedia.com - rs1358054"] = "https://www.snpedia.com/index.php/Rs1358054"
locusReferencesMap[1358054] = locus19_ReferencesMap
locus20_ReferencesMap := make(map[string]string)
locus20_ReferencesMap["SNPedia.com - rs722628"] = "https://www.snpedia.com/index.php/Rs722628"
locusReferencesMap[722628] = locus20_ReferencesMap
locus21_ReferencesMap := make(map[string]string)
locus21_ReferencesMap["SNPedia.com - rs536861"] = "https://www.snpedia.com/index.php/Rs536861"
locusReferencesMap[536861] = locus21_ReferencesMap
locus22_ReferencesMap := make(map[string]string)
locus22_ReferencesMap["SNPedia.com - rs757972971"] = "https://www.snpedia.com/index.php/Rs757972971"
locusReferencesMap[757972971] = locus22_ReferencesMap
referencesMap_LocusList1 := make(map[string]string)
referencesMap_LocusList1["Understanding the impact of SNPs associated with autism spectrum disorder on biological pathways in the human fetal and adult cortex"] = "https://www.nature.com/articles/s41598-021-95447-z"
lociList1 := []int64{
13217619,
115329265,
116137698,
141342723,
75782365,
151267808,
7746199,
114115252,
4298967,
1782810,
6921919,
9467711,
115707823,
116633139,
115123779,
116326873,
9834970,
144762289,
9348739,
4481150,
12129573,
116408368,
11191419,
115242751,
116385615,
114882497,
114867672,
12658451,
202906,
13212562,
7085104,
1702294,
114276265,
116427960,
59574136,
114041423,
7531118,
114964506,
111639056,
6939532,
6940116,
116663187,
114904464,
145547914,
9269271,
114963521,
140502984,
61867293,
115035678,
9274390,
11688767,
78110044,
150680405,
10883832,
7752195,
115497191,
116676919,
11191582,
115344853,
144911693,
71395455,
5758265,
2007044,
149979052,
115682897,
3001723,
1024582,
115625073,
9273177,
61472021,
12668848,
184153866,
115558405,
150430679,
115687605,
35324223,
9274299,
138984909,
145076523,
55661361,
911186,
144304366,
10149470,
144660248,
13218591,
114455101,
185717927,
144649399,
114086406,
11682175,
142972412,
138748649,
7405404,
11693528,
12958048,
35225200,
114950038,
140865314,
4129585,
12887734,
36057735,
115052633,
186129480,
2507989,
2021722,
140505938,
2388334,
3617,
114274203,
281768,
115937317,
144018888,
2535629,
4906364,
180778602,
707939,
8084351,
80318442,
186229361,
9461856,
113397282,
28681284,
113205291,
2851447,
4380187,
115960997,
1793889,
142790902,
111312615,
144532965,
75968099,
115661163,
1518367,
193267147,
41293179,
200986,
34787248,
140364877,
13240464,
1625579,
4702,
2514218,
778353,
325506,
182908437,
149721896,
6434928,
4713071,
11753207,
191843781,
116182620,
2760981,
116067082,
142601889,
147976543,
116254153,
8054556,
114204022,
115165987,
9636107,
41563,
35828350,
764284,
115325719,
7193263,
149915948,
17843707,
79879286,
631399,
732381,
1150688,
189600472,
3798869,
5757717,
145501595,
4642619,
117616320,
12704290,
2176546,
149787317,
11570190,
4391122,
7071123,
12712388,
4307059,
369637,
114291394,
11740474,
12925872,
116460775,
114838832,
10791097,
35610290,
114812317,
9469174,
7801375,
114508985,
6704768,
4580973,
147875011,
7893279,
12966547,
9922678,
111294930,
6047287,
34215985,
2693698,
12826178,
2237234,
11210892,
67756423,
9787523,
10108980,
2057884,
1498232,
8042374,
142520578,
114771361,
114810457,
17194490,
145470632,
36063234,
2332700,
1615350,
3735025,
115283957,
75059851,
1730054,
116593970,
4523957,
169738,
35346733,
12954356,
7907645,
2910032,
9270074,
1899546,
6071524,
11874716,
72761442,
3132556,
116139966,
139547629,
28724212,
6855246,
72934570,
147793969,
115487448,
4619651,
7521492,
2103655,
880090,
1806153,
11787216,
115915654,
11223651,
62378245,
8009147,
7191183,
77502336,
3849046,
1131275,
61747867,
116047537,
41293330,
61789073,
7914558,
10043984,
10514301,
117956829,
4647903,
4916723,
28669119,
35774874,
4244354,
1452075,
56223946,
2434529,
115641444,
149998036,
184123737,
10994359,
9360557,
80256351,
6125656,
247910,
3812984,
915057,
17659437,
11641947,
139099016,
72687362,
57709857,
11210195,
3020736,
12592967,
5995756,
385492,
115443066,
9371601,
59979824,
6694545,
1484144,
832190,
9267057,
4309187,
149544854,
116502302,
191269336,
1006737,
10265001,
6969410,
1080500,
171748,
139480376,
17292804,
174592,
1620977,
184538485,
191239160,
301798,
10211550,
10994397,
9677504,
144158419,
2098651,
8321,
11231640,
77135925,
12474906,
2300861,
2391769,
10520163,
9607782,
55648125,
10099100,
16854048,
35131895,
1977199,
145607970,
115569272,
116552815,
6803008,
35998080,
10791111,
2944591,
1353545,
115437294,
133047,
9274657,
11191580,
11191454,
7618871,
10745841,
61882743,
116755193,
142462188,
7200826,
27419,
2414718,
2842198,
12552,
395138,
760648,
1002656,
2898883,
13072940,
12443170,
114441450,
146201420,
184981897,
138850297,
8032315,
7184114,
115136442,
2767713,
2828478,
9879311,
114142645,
111977918,
7819570,
12522290,
112209031,
10491964,
11658257,
62526783,
6471814,
11866581,
12894153,
2391734,
2522831,
2003490,
301799,
1226412,
1950829,
8453,
926938,
6537825,
111931861,
115963308,
149961934,
61847307,
146827975,
1339227,
36350,
7432375,
9656169,
28758902,
427691,
2293751,
182087722,
73416724,
61884307,
188190243,
41294271,
114830752,
7004633,
7785663,
8066384,
188099135,
4730387,
11887562,
2801578,
4242470,
746839,
3827735,
11582563,
11102807,
7511633,
11102800,
11585926,
6661053,
11589568,
4141463,
201910565,
71190156,
353547,
880446,
2115780,
114277634,
140849564,
76994193,
114875775,
7122181,
221902,
12576775,
10503253,
2799573,
4495234,
4526442,
4682973,
12898460,
2047568,
2910032,
1501361,
}
for _, rsID := range lociList1{
existingMap, exists := locusReferencesMap[rsID]
if (exists == false){
locusReferencesMap[rsID] = maps.Clone(referencesMap_LocusList1)
} else {
// We merge the maps
for key, value := range referencesMap_LocusList1{
existingMap[key] = value
}
locusReferencesMap[rsID] = existingMap
}
}
return locusReferencesMap
}

View file

@ -199,6 +199,7 @@ func TestGeneticReferences(t *testing.T){
diseaseName := diseaseObject.DiseaseName
diseaseDescription := diseaseObject.DiseaseDescription
diseaseEffectedSex := diseaseObject.EffectedSex
diseaseLocusReferencesMap := diseaseObject.LocusReferencesMap
diseaseLociList := diseaseObject.LociList
diseaseReferencesMap := diseaseObject.References
@ -218,82 +219,34 @@ func TestGeneticReferences(t *testing.T){
t.Fatalf("PolygenicDisease effected sex is invalid: " + diseaseEffectedSex)
}
for rsID, referencesMap := range diseaseLocusReferencesMap{
containsItem := slices.Contains(diseaseLociList, rsID)
if (containsItem == false){
t.Fatalf("Polygenic disease diseaseLocusReferencesMap contains disease locus that is not inside of the disease's loci list.")
}
allRSIDsMap[rsID] = struct{}{}
referencesAreValid := verifyReferencesMap(referencesMap)
if (referencesAreValid == false){
t.Fatalf("PolygenicDisease references map is invalid for disease locus.")
}
}
containsDuplicates, _ := helpers.CheckIfListContainsDuplicates(diseaseLociList)
if (containsDuplicates == true){
t.Fatalf("Polygenic disease object contains diseaseLociList with duplicate rsIDs.")
}
if (len(diseaseLocusReferencesMap) > len(diseaseLociList)){
t.Fatalf("Polygenic disease contains locus references map that is longer than the diseaseLociList")
}
referencesAreValid := verifyReferencesMap(diseaseReferencesMap)
if (referencesAreValid == false){
t.Fatalf("PolygenicDisease references map is invalid for disease: " + diseaseName)
}
// We use this map to make sure each disease locus references a unique rsid
allPolygenicDiseaseRSIDsMap := make(map[int64]struct{})
for _, locusObject := range diseaseLociList{
locusIdentifier := locusObject.LocusIdentifier
locusRSID := locusObject.LocusRSID
riskWeightsMap := locusObject.RiskWeightsMap
oddsRatiosMap := locusObject.OddsRatiosMap
minimumWeight := locusObject.MinimumRiskWeight
maximumWeight := locusObject.MaximumRiskWeight
allRSIDsMap[locusRSID] = struct{}{}
identifierIsValid := verifyIdentifier(locusIdentifier)
if (identifierIsValid == false){
t.Fatalf(diseaseName + " Invalid locus identifier found: " + locusIdentifier)
}
_, exists := allIdentifiersMap[locusIdentifier]
if (exists == true){
t.Fatalf(diseaseName + " Duplicate locus identifier found: " + locusIdentifier)
}
allIdentifiersMap[locusIdentifier] = struct{}{}
_, exists = allPolygenicDiseaseRSIDsMap[locusRSID]
if (exists == true){
rsidString := helpers.ConvertInt64ToString(locusRSID)
t.Fatalf(diseaseName + " RSID Collision found: " + rsidString)
}
allPolygenicDiseaseRSIDsMap[locusRSID] = struct{}{}
if (len(riskWeightsMap) == 0){
t.Fatalf("Empty base weights map found: " + locusIdentifier)
}
trueMinimumWeight := 100000
trueMaximumWeight := -100000
for basePair, basePairWeight := range riskWeightsMap{
isValid := verifyBasePair(basePair)
if (isValid == false){
t.Fatalf("Base pair weights map contains invalid base pair: " + locusIdentifier)
}
if (basePairWeight < trueMinimumWeight){
trueMinimumWeight = basePairWeight
}
if (basePairWeight > trueMaximumWeight){
trueMaximumWeight = basePairWeight
}
}
if (trueMinimumWeight != minimumWeight){
t.Fatalf(diseaseName + ": Invalid minimum base pair weight found: " + locusIdentifier)
}
if (trueMaximumWeight != maximumWeight){
t.Fatalf(diseaseName + ": Invalid maximum base pair weight found: " + locusIdentifier)
}
for basePair, _ := range oddsRatiosMap{
isValid := verifyBasePair(basePair)
if (isValid == false){
t.Fatalf("Odds ratio weights map contains invalid base pair: " + locusIdentifier)
}
}
//TODO: Make sure that duplicate base pairs have same weight, odds ratios and probabilities
}
}
err = traits.InitializeTraitVariables()

View file

@ -43,7 +43,8 @@ func AddLocusMetadata(inputLociToAddList []locusMetadata.LocusMetadata)(int, []b
_, exists := newLocusMetadataRSIDsMap[rsID]
if (exists == true){
return 0, nil, errors.New("inputLociToAddList contains multiple locus metadatas with a duplicate rsID.")
rsIDString := helpers.ConvertInt64ToString(rsID)
return 0, nil, errors.New("inputLociToAddList contains multiple locus metadatas with a duplicate rsID: " + rsIDString)
}
newLocusMetadataRSIDsMap[rsID] = struct{}{}

View file

@ -0,0 +1,51 @@
package polygenicDiseases
import "errors"
import "seekia/resources/geneticReferences/attributeLoci"
import "seekia/internal/helpers"
func getAutismDiseaseObject()PolygenicDisease{
autismLocusReferencesMap := attributeLoci.GetAutismLoci()
autismLociList := helpers.GetListOfMapKeys(autismLocusReferencesMap)
referencesMap := make(map[string]string)
referencesMap["SNPedia.com - Autism"] = "https://www.snpedia.com/index.php/Autism"
// https://www.cdc.gov/mmwr/volumes/72/ss/ss7202a1.htm
// For 2020, one in 36 children aged 8 years (approximately 4% of boys and 1% of girls) was estimated to have ASD.
getAverageRiskProbabilitiesFunction := func(maleOrFemale string, inputAge int)(float64, error){
if (maleOrFemale == "Male"){
return 0.04, nil
}
if (maleOrFemale != "Female"){
return 0, errors.New("Trying to get breast cancer risk probability for invalid maleOrFemale: " + maleOrFemale)
}
//TODO: Add different probabilities per age
return 0.01, nil
}
autismObject := PolygenicDisease{
DiseaseName: "Autism",
EffectedSex: "Both",
DiseaseDescription: "A mental disorder characterized by inability to engage in normal social interactions and intense self-absorption, and usually accompanied by other symptoms such as language dysfunctions and repetitive behavior.",
// Taken from: The American Heritage® Dictionary of the English Language, 5th Edition
LocusReferencesMap: autismLocusReferencesMap,
LociList: autismLociList,
GetAverageRiskProbabilitiesFunction: getAverageRiskProbabilitiesFunction,
References: referencesMap,
}
return autismObject
}

View file

@ -2,863 +2,143 @@ package polygenicDiseases
import "errors"
import "seekia/internal/helpers"
func getBreastCancerDiseaseObject()PolygenicDisease{
// Map Structure: rsID -> (map[Reference Name]Reference Link)
locusReferencesMap := make(map[int64]map[string]string)
locus1_ReferencesMap := make(map[string]string)
locus1_ReferencesMap["SNPedia.com - rs16942"] = "https://www.snpedia.com/index.php/Rs16942"
locus1_RiskWeightsMap := make(map[string]int)
locus1_RiskWeightsMap["T;T"] = 0
locus1_RiskWeightsMap["T;C"] = 1
locus1_RiskWeightsMap["C;T"] = 1
locus1_RiskWeightsMap["C;C"] = 1
locus1_OddsRatiosMap := make(map[string]float64)
locus1_OddsRatiosMap["T;T"] = 1
locus1_OddsRatiosMap["T;C"] = 1.14
locus1_OddsRatiosMap["C;T"] = 1.14
locus1_OddsRatiosMap["C;C"] = 1.28
locus1_BasePairProbabilitiesMap := make(map[string]float64)
locus1_BasePairProbabilitiesMap["T;T"] = .45
locus1_BasePairProbabilitiesMap["T;C"] = .45
locus1_BasePairProbabilitiesMap["C;T"] = .45
locus1_BasePairProbabilitiesMap["C;C"] = .10
locus1_Object := DiseaseLocus{
LocusIdentifier: "d7891c",
LocusRSID: 16942,
RiskWeightsMap: locus1_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 1,
OddsRatiosMap: locus1_OddsRatiosMap,
BasePairProbabilitiesMap: locus1_BasePairProbabilitiesMap,
References: locus1_ReferencesMap,
}
locusReferencesMap[16942] = locus1_ReferencesMap
locus2_ReferencesMap := make(map[string]string)
locus2_ReferencesMap["SNPedia.com - rs1045485"] = "https://www.snpedia.com/index.php/Rs1045485"
locus2_RiskWeightsMap := make(map[string]int)
locus2_RiskWeightsMap["C;C"] = -2
locus2_RiskWeightsMap["C;G"] = -1
locus2_RiskWeightsMap["G;C"] = -1
locus2_RiskWeightsMap["G;G"] = 0
locus2_OddsRatiosMap := make(map[string]float64)
locus2_OddsRatiosMap["C;C"] = 0.74
locus2_OddsRatiosMap["C;G"] = 0.89
locus2_OddsRatiosMap["G;C"] = 0.89
locus2_OddsRatiosMap["G;G"] = 1
locus2_BasePairProbabilitiesMap := make(map[string]float64)
locus2_BasePairProbabilitiesMap["C;C"] = .01
locus2_BasePairProbabilitiesMap["C;G"] = .04
locus2_BasePairProbabilitiesMap["G;C"] = .04
locus2_BasePairProbabilitiesMap["G;G"] = .95
locus2_Object := DiseaseLocus{
LocusIdentifier: "41c164",
LocusRSID: 1045485,
RiskWeightsMap: locus2_RiskWeightsMap,
MinimumRiskWeight: -2,
MaximumRiskWeight: 0,
OddsRatiosMap: locus2_OddsRatiosMap,
BasePairProbabilitiesMap: locus2_BasePairProbabilitiesMap,
References: locus2_ReferencesMap,
}
locusReferencesMap[1045485] = locus2_ReferencesMap
locus3_ReferencesMap := make(map[string]string)
locus3_ReferencesMap["SNPedia.com - rs34330"] = "https://www.snpedia.com/index.php/Rs34330"
locus3_RiskWeightsMap := make(map[string]int)
locus3_RiskWeightsMap["C;C"] = 0
locus3_RiskWeightsMap["T;T"] = 1
locus3_OddsRatiosMap := make(map[string]float64)
locus3_OddsRatiosMap["C;C"] = 0
locus3_OddsRatiosMap["T;T"] = 1.22
locus3_BasePairProbabilitiesMap := make(map[string]float64)
locus3_BasePairProbabilitiesMap["C;C"] = .40
locus3_BasePairProbabilitiesMap["C;T"] = .45
locus3_BasePairProbabilitiesMap["T;C"] = .45
locus3_BasePairProbabilitiesMap["T;T"] = .15
locus3_Object := DiseaseLocus{
LocusIdentifier: "f3a097",
LocusRSID: 34330,
RiskWeightsMap: locus3_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 1,
OddsRatiosMap: locus3_OddsRatiosMap,
BasePairProbabilitiesMap: locus3_BasePairProbabilitiesMap,
References: locus3_ReferencesMap,
}
locusReferencesMap[34330] = locus3_ReferencesMap
locus4_ReferencesMap := make(map[string]string)
locus4_ReferencesMap["SNPedia.com - rs144848"] = "https://www.snpedia.com/index.php/Rs144848"
locus4_RiskWeightsMap := make(map[string]int)
locus4_RiskWeightsMap["A;A"] = 0
locus4_RiskWeightsMap["C;A"] = 1
locus4_RiskWeightsMap["A;C"] = 1
locus4_RiskWeightsMap["C;C"] = 2
locus4_OddsRatiosMap := make(map[string]float64)
locus4_OddsRatiosMap["A;A"] = 1
locus4_OddsRatiosMap["A;C"] = 1.14
locus4_OddsRatiosMap["C;A"] = 1.14
locus4_OddsRatiosMap["C;C"] = 1.31
locus4_BasePairProbabilitiesMap := make(map[string]float64)
locus4_BasePairProbabilitiesMap["A;A"] = .55
locus4_BasePairProbabilitiesMap["C;A"] = .36
locus4_BasePairProbabilitiesMap["A;C"] = .36
locus4_BasePairProbabilitiesMap["C;C"] = .09
locus4_Object := DiseaseLocus{
LocusIdentifier: "d4626f",
LocusRSID: 144848,
RiskWeightsMap: locus4_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus4_OddsRatiosMap,
BasePairProbabilitiesMap: locus4_BasePairProbabilitiesMap,
References: locus4_ReferencesMap,
}
locusReferencesMap[144848] = locus4_ReferencesMap
locus5_ReferencesMap := make(map[string]string)
locus5_ReferencesMap["SNPedia.com - rs766173"] = "https://www.snpedia.com/index.php/Rs766173"
locus5_RiskWeightsMap := make(map[string]int)
locus5_RiskWeightsMap["A;A"] = 0
locus5_RiskWeightsMap["A;C"] = 1
locus5_RiskWeightsMap["C;A"] = 1
locus5_RiskWeightsMap["C;C"] = 2
locus5_OddsRatiosMap := make(map[string]float64)
locus5_OddsRatiosMap["A;A"] = 1
locus5_OddsRatiosMap["A;C"] = 1.14
locus5_OddsRatiosMap["C;A"] = 1.14
locus5_OddsRatiosMap["C;C"] = 1.28
locus5_BasePairProbabilitiesMap := make(map[string]float64)
locus5_BasePairProbabilitiesMap["A;A"] = .85
locus5_BasePairProbabilitiesMap["A;C"] = .13
locus5_BasePairProbabilitiesMap["C;A"] = .13
locus5_BasePairProbabilitiesMap["C;C"] = .02
locus5_Object := DiseaseLocus{
LocusIdentifier: "84aaa4",
LocusRSID: 766173,
RiskWeightsMap: locus5_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus5_OddsRatiosMap,
BasePairProbabilitiesMap: locus5_BasePairProbabilitiesMap,
References: locus5_ReferencesMap,
}
locusReferencesMap[766173] = locus5_ReferencesMap
locus6_ReferencesMap := make(map[string]string)
locus6_ReferencesMap["SNPedia.com - rs1799950"] = "https://www.snpedia.com/index.php/Rs1799950"
locus6_RiskWeightsMap := make(map[string]int)
locus6_RiskWeightsMap["T;T"] = 0
locus6_RiskWeightsMap["T;C"] = 1
locus6_RiskWeightsMap["C;T"] = 1
locus6_RiskWeightsMap["C;C"] = 2
locus6_OddsRatiosMap := make(map[string]float64)
locus6_OddsRatiosMap["T;T"] = 1
locus6_OddsRatiosMap["T;C"] = 1.5
locus6_OddsRatiosMap["C;T"] = 1.5
locus6_OddsRatiosMap["C;C"] = 1.72
locus6_BasePairProbabilitiesMap := make(map[string]float64)
locus6_BasePairProbabilitiesMap["T;T"] = .98
locus6_BasePairProbabilitiesMap["T;C"] = .02
locus6_BasePairProbabilitiesMap["C;T"] = .02
locus6_BasePairProbabilitiesMap["C;C"] = .001
locus6_Object := DiseaseLocus{
LocusIdentifier: "c8de7a",
LocusRSID: 1799950,
RiskWeightsMap: locus6_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus6_OddsRatiosMap,
BasePairProbabilitiesMap: locus6_BasePairProbabilitiesMap,
References: locus6_ReferencesMap,
}
locusReferencesMap[1799950] = locus6_ReferencesMap
locus7_ReferencesMap := make(map[string]string)
locus7_ReferencesMap["SNPedia.com - rs4986850"] = "https://www.snpedia.com/index.php/Rs4986850"
locus7_RiskWeightsMap := make(map[string]int)
locus7_RiskWeightsMap["C;C"] = 0
locus7_RiskWeightsMap["T;C"] = 1
locus7_RiskWeightsMap["C;T"] = 1
locus7_RiskWeightsMap["T;T"] = 2
locus7_OddsRatiosMap := make(map[string]float64)
locus7_OddsRatiosMap["C;C"] = 1
locus7_OddsRatiosMap["T;C"] = 1.14
locus7_OddsRatiosMap["C;T"] = 1.14
locus7_OddsRatiosMap["T;T"] = 1.28
locus7_BasePairProbabilitiesMap := make(map[string]float64)
locus7_BasePairProbabilitiesMap["C;C"] = .92
locus7_BasePairProbabilitiesMap["T;C"] = .07
locus7_BasePairProbabilitiesMap["C;T"] = .07
locus7_BasePairProbabilitiesMap["T;T"] = .01
locus7_Object := DiseaseLocus{
LocusIdentifier: "d30087",
LocusRSID: 4986850,
RiskWeightsMap: locus7_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus7_OddsRatiosMap,
BasePairProbabilitiesMap: locus7_BasePairProbabilitiesMap,
References: locus7_ReferencesMap,
}
locusReferencesMap[4986850] = locus7_ReferencesMap
locus8_ReferencesMap := make(map[string]string)
locus8_ReferencesMap["SNPedia.com - rs2227945"] = "https://www.snpedia.com/index.php/Rs2227945"
locus8_RiskWeightsMap := make(map[string]int)
locus8_RiskWeightsMap["T;T"] = 0
locus8_RiskWeightsMap["T;C"] = 1
locus8_RiskWeightsMap["C;T"] = 1
locus8_RiskWeightsMap["C;C"] = 2
locus8_OddsRatiosMap := make(map[string]float64)
locus8_OddsRatiosMap["T;T"] = 1
locus8_OddsRatiosMap["T;C"] = 1.14
locus8_OddsRatiosMap["C;T"] = 1.14
locus8_OddsRatiosMap["C;C"] = 1.28
locus8_BasePairProbabilitiesMap := make(map[string]float64)
locus8_BasePairProbabilitiesMap["T;T"] = .97
locus8_BasePairProbabilitiesMap["T;C"] = .03
locus8_BasePairProbabilitiesMap["C;T"] = .03
locus8_BasePairProbabilitiesMap["C;C"] = .001
locus8_Object := DiseaseLocus{
LocusIdentifier: "cafa72",
LocusRSID: 2227945,
RiskWeightsMap: locus8_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus8_OddsRatiosMap,
BasePairProbabilitiesMap: locus8_BasePairProbabilitiesMap,
References: locus8_ReferencesMap,
}
locusReferencesMap[2227945] = locus8_ReferencesMap
locus9_ReferencesMap := make(map[string]string)
locus9_ReferencesMap["SNPedia.com - rs1799966"] = "https://www.snpedia.com/index.php/Rs1799966"
locus9_RiskWeightsMap := make(map[string]int)
locus9_RiskWeightsMap["T;T"] = 0
locus9_RiskWeightsMap["T;C"] = 1
locus9_RiskWeightsMap["C;T"] = 1
locus9_RiskWeightsMap["C;C"] = 2
locus9_OddsRatiosMap := make(map[string]float64)
locus9_OddsRatiosMap["T;T"] = 1
locus9_OddsRatiosMap["T;C"] = 1.14
locus9_OddsRatiosMap["C;T"] = 1.14
locus9_OddsRatiosMap["C;C"] = 1.28
locus9_BasePairProbabilitiesMap := make(map[string]float64)
locus9_BasePairProbabilitiesMap["T;T"] = .45
locus9_BasePairProbabilitiesMap["T;C"] = .45
locus9_BasePairProbabilitiesMap["C;T"] = .45
locus9_BasePairProbabilitiesMap["C;C"] = .10
locus9_Object := DiseaseLocus{
LocusIdentifier: "8f671c",
LocusRSID: 1799966,
RiskWeightsMap: locus9_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus9_OddsRatiosMap,
BasePairProbabilitiesMap: locus9_BasePairProbabilitiesMap,
References: locus9_ReferencesMap,
}
locusReferencesMap[1799966] = locus9_ReferencesMap
locus10_ReferencesMap := make(map[string]string)
locus10_ReferencesMap["SNPedia.com - rs4987117"] = "https://www.snpedia.com/index.php/Rs4987117"
locus10_RiskWeightsMap := make(map[string]int)
locus10_RiskWeightsMap["C;C"] = 0
locus10_RiskWeightsMap["T;C"] = 1
locus10_RiskWeightsMap["C;T"] = 1
locus10_RiskWeightsMap["T;T"] = 2
locus10_OddsRatiosMap := make(map[string]float64)
locus10_OddsRatiosMap["C;C"] = 1
locus10_OddsRatiosMap["T;C"] = 1.14
locus10_OddsRatiosMap["C;T"] = 1.14
locus10_OddsRatiosMap["T;T"] = 1.28
locus10_BasePairProbabilitiesMap := make(map[string]float64)
locus10_BasePairProbabilitiesMap["C;C"] = .98
locus10_BasePairProbabilitiesMap["T;C"] = .02
locus10_BasePairProbabilitiesMap["C;T"] = .02
locus10_BasePairProbabilitiesMap["T;T"] = .001
locus10_Object := DiseaseLocus{
LocusIdentifier: "b3e49a",
LocusRSID: 4987117,
RiskWeightsMap: locus10_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus10_OddsRatiosMap,
BasePairProbabilitiesMap: locus10_BasePairProbabilitiesMap,
References: locus10_ReferencesMap,
}
locusReferencesMap[4987117] = locus10_ReferencesMap
locus11_ReferencesMap := make(map[string]string)
locus11_ReferencesMap["SNPedia.com - rs1799954"] = "https://www.snpedia.com/index.php/Rs1799954"
locus11_RiskWeightsMap := make(map[string]int)
locus11_RiskWeightsMap["C;C"] = 0
locus11_RiskWeightsMap["T;C"] = 1
locus11_RiskWeightsMap["C;T"] = 1
locus11_RiskWeightsMap["T;T"] = 2
locus11_OddsRatiosMap := make(map[string]float64)
locus11_OddsRatiosMap["C;C"] = 1
locus11_OddsRatiosMap["T;C"] = 1.14
locus11_OddsRatiosMap["C;T"] = 1.14
locus11_OddsRatiosMap["T;T"] = 1.28
locus11_BasePairProbabilitiesMap := make(map[string]float64)
locus11_BasePairProbabilitiesMap["C;C"] = .97
locus11_BasePairProbabilitiesMap["T;C"] = .03
locus11_BasePairProbabilitiesMap["C;T"] = .03
locus11_BasePairProbabilitiesMap["T;T"] = .001
locus11_Object := DiseaseLocus{
LocusIdentifier: "8b0b02",
LocusRSID: 1799954,
RiskWeightsMap: locus11_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus11_OddsRatiosMap,
BasePairProbabilitiesMap: locus11_BasePairProbabilitiesMap,
References: locus11_ReferencesMap,
}
locusReferencesMap[1799954] = locus11_ReferencesMap
locus12_ReferencesMap := make(map[string]string)
locus12_ReferencesMap["SNPedia.com - rs11571746"] = "https://www.snpedia.com/index.php/Rs11571746"
locus12_RiskWeightsMap := make(map[string]int)
locus12_RiskWeightsMap["T;T"] = 0
locus12_RiskWeightsMap["T;C"] = 1
locus12_RiskWeightsMap["C;T"] = 1
locus12_RiskWeightsMap["C;C"] = 2
locus12_OddsRatiosMap := make(map[string]float64)
locus12_OddsRatiosMap["T;T"] = 1
locus12_OddsRatiosMap["T;C"] = 1.14
locus12_OddsRatiosMap["C;T"] = 1.14
locus12_OddsRatiosMap["C;C"] = 1.28
locus12_BasePairProbabilitiesMap := make(map[string]float64)
locus12_BasePairProbabilitiesMap["T;T"] = .98
locus12_BasePairProbabilitiesMap["T;C"] = .02
locus12_BasePairProbabilitiesMap["C;T"] = .02
locus12_BasePairProbabilitiesMap["C;C"] = .001
locus12_Object := DiseaseLocus{
LocusIdentifier: "25cafc",
LocusRSID: 11571746,
RiskWeightsMap: locus12_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus12_OddsRatiosMap,
BasePairProbabilitiesMap: locus12_BasePairProbabilitiesMap,
References: locus12_ReferencesMap,
}
locusReferencesMap[11571746] = locus12_ReferencesMap
locus13_ReferencesMap := make(map[string]string)
locus13_ReferencesMap["SNPedia.com - rs11571747"] = "https://www.snpedia.com/index.php/Rs11571747"
locus13_RiskWeightsMap := make(map[string]int)
locus13_RiskWeightsMap["A;A"] = 0
locus13_RiskWeightsMap["A;C"] = 1
locus13_RiskWeightsMap["C;A"] = 1
locus13_RiskWeightsMap["C;C"] = 2
locus13_OddsRatiosMap := make(map[string]float64)
locus13_OddsRatiosMap["A;A"] = 1
locus13_OddsRatiosMap["A;C"] = 1.14
locus13_OddsRatiosMap["C;A"] = 1.14
locus13_OddsRatiosMap["C;C"] = 1.28
locus13_BasePairProbabilitiesMap := make(map[string]float64)
locus13_BasePairProbabilitiesMap["A;A"] = .99
locus13_BasePairProbabilitiesMap["A;C"] = .001
locus13_BasePairProbabilitiesMap["C;A"] = .001
locus13_BasePairProbabilitiesMap["C;C"] = .001
locus13_Object := DiseaseLocus{
LocusIdentifier: "34c7e5",
LocusRSID: 11571747,
RiskWeightsMap: locus13_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus13_OddsRatiosMap,
BasePairProbabilitiesMap: locus13_BasePairProbabilitiesMap,
References: locus13_ReferencesMap,
}
locusReferencesMap[11571747] = locus13_ReferencesMap
locus14_ReferencesMap := make(map[string]string)
locus14_ReferencesMap["SNPedia.com - rs4987047"] = "https://www.snpedia.com/index.php/Rs4987047"
locus14_RiskWeightsMap := make(map[string]int)
locus14_RiskWeightsMap["A;A"] = 0
locus14_RiskWeightsMap["A;T"] = 1
locus14_RiskWeightsMap["T;A"] = 1
locus14_RiskWeightsMap["T;T"] = 2
locus14_OddsRatiosMap := make(map[string]float64)
locus14_OddsRatiosMap["A;A"] = 1
locus14_OddsRatiosMap["A;T"] = 1.14
locus14_OddsRatiosMap["T;A"] = 1.14
locus14_OddsRatiosMap["T;T"] = 1.28
locus14_BasePairProbabilitiesMap := make(map[string]float64)
locus14_BasePairProbabilitiesMap["A;A"] = .94
locus14_BasePairProbabilitiesMap["A;T"] = .94
locus14_BasePairProbabilitiesMap["T;A"] = .05
locus14_BasePairProbabilitiesMap["T;T"] = .01
locus14_Object := DiseaseLocus{
LocusIdentifier: "60ce27",
LocusRSID: 4987047,
RiskWeightsMap: locus14_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus14_OddsRatiosMap,
BasePairProbabilitiesMap: locus14_BasePairProbabilitiesMap,
References: locus14_ReferencesMap,
}
locusReferencesMap[4987047] = locus14_ReferencesMap
locus15_ReferencesMap := make(map[string]string)
locus15_ReferencesMap["SNPedia.com - rs11571833"] = "https://www.snpedia.com/index.php/Rs11571833"
locus15_RiskWeightsMap := make(map[string]int)
locus15_RiskWeightsMap["A;A"] = 0
locus15_RiskWeightsMap["T;A"] = 1
locus15_RiskWeightsMap["A;T"] = 1
locus15_RiskWeightsMap["T;T"] = 2
locus15_OddsRatiosMap := make(map[string]float64)
locus15_OddsRatiosMap["A;A"] = 1
locus15_OddsRatiosMap["T;A"] = 1.14
locus15_OddsRatiosMap["A;T"] = 1.14
locus15_OddsRatiosMap["T;T"] = 1.28
locus15_BasePairProbabilitiesMap := make(map[string]float64)
locus15_BasePairProbabilitiesMap["A;A"] = .99
locus15_BasePairProbabilitiesMap["T;A"] = .01
locus15_BasePairProbabilitiesMap["A;T"] = .01
locus15_BasePairProbabilitiesMap["T;T"] = .001
locus15_Object := DiseaseLocus{
LocusIdentifier: "328cdf",
LocusRSID: 11571833,
RiskWeightsMap: locus15_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus15_OddsRatiosMap,
BasePairProbabilitiesMap: locus15_BasePairProbabilitiesMap,
References: locus15_ReferencesMap,
}
locusReferencesMap[11571833] = locus15_ReferencesMap
locus16_ReferencesMap := make(map[string]string)
locus16_ReferencesMap["SNPedia.com - rs1801426"] = "https://www.snpedia.com/index.php/Rs1801426"
locus16_RiskWeightsMap := make(map[string]int)
locus16_RiskWeightsMap["A;A"] = 0
locus16_RiskWeightsMap["G;A"] = 1
locus16_RiskWeightsMap["A;G"] = 1
locus16_RiskWeightsMap["G;G"] = 2
locus16_OddsRatiosMap := make(map[string]float64)
locus16_OddsRatiosMap["A;A"] = 1
locus16_OddsRatiosMap["G;A"] = 1.14
locus16_OddsRatiosMap["A;G"] = 1.14
locus16_OddsRatiosMap["G;G"] = 1.28
locus16_BasePairProbabilitiesMap := make(map[string]float64)
locus16_BasePairProbabilitiesMap["A;A"] = .90
locus16_BasePairProbabilitiesMap["G;A"] = .09
locus16_BasePairProbabilitiesMap["A;G"] = .09
locus16_BasePairProbabilitiesMap["G;G"] = .01
locus16_Object := DiseaseLocus{
LocusIdentifier: "849bc7",
LocusRSID: 1801426,
RiskWeightsMap: locus16_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus16_OddsRatiosMap,
BasePairProbabilitiesMap: locus16_BasePairProbabilitiesMap,
References: locus16_ReferencesMap,
}
locusReferencesMap[1801426] = locus16_ReferencesMap
locus17_ReferencesMap := make(map[string]string)
locus17_ReferencesMap["SNPedia.com - rs3218707"] = "https://www.snpedia.com/index.php/Rs3218707"
locus17_RiskWeightsMap := make(map[string]int)
locus17_RiskWeightsMap["G;G"] = 0
locus17_RiskWeightsMap["G;C"] = 1
locus17_RiskWeightsMap["C;G"] = 1
locus17_RiskWeightsMap["C;C"] = 2
locus17_OddsRatiosMap := make(map[string]float64)
locus17_OddsRatiosMap["G;G"] = 1
locus17_OddsRatiosMap["G;C"] = 1.14
locus17_OddsRatiosMap["C;G"] = 1.14
locus17_OddsRatiosMap["C;C"] = 1.28
locus17_BasePairProbabilitiesMap := make(map[string]float64)
locus17_BasePairProbabilitiesMap["G;G"] = .96
locus17_BasePairProbabilitiesMap["G;C"] = .04
locus17_BasePairProbabilitiesMap["C;G"] = .04
locus17_BasePairProbabilitiesMap["C;C"] = .001
locus17_Object := DiseaseLocus{
LocusIdentifier: "5af5e3",
LocusRSID: 3218707,
RiskWeightsMap: locus17_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus17_OddsRatiosMap,
BasePairProbabilitiesMap: locus17_BasePairProbabilitiesMap,
References: locus17_ReferencesMap,
}
locusReferencesMap[3218707] = locus17_ReferencesMap
locus18_ReferencesMap := make(map[string]string)
locus18_ReferencesMap["SNPedia.com - rs4987945"] = "https://www.snpedia.com/index.php/Rs4987945"
locus18_RiskWeightsMap := make(map[string]int)
locus18_RiskWeightsMap["C;C"] = 0
locus18_RiskWeightsMap["C;G"] = 1
locus18_RiskWeightsMap["G;C"] = 1
locus18_RiskWeightsMap["G;G"] = 2
locus18_OddsRatiosMap := make(map[string]float64)
locus18_OddsRatiosMap["C;C"] = 1
locus18_OddsRatiosMap["C;G"] = 1.14
locus18_OddsRatiosMap["G;C"] = 1.14
locus18_OddsRatiosMap["G;G"] = 1.28
locus18_BasePairProbabilitiesMap := make(map[string]float64)
locus18_BasePairProbabilitiesMap["C;C"] = .95
locus18_BasePairProbabilitiesMap["C;G"] = .04
locus18_BasePairProbabilitiesMap["G;C"] = .04
locus18_BasePairProbabilitiesMap["G;G"] = .01
locus18_Object := DiseaseLocus{
LocusIdentifier: "c354fa",
LocusRSID: 4987945,
RiskWeightsMap: locus18_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus18_OddsRatiosMap,
BasePairProbabilitiesMap: locus18_BasePairProbabilitiesMap,
References: locus18_ReferencesMap,
}
locusReferencesMap[4987945] = locus18_ReferencesMap
locus19_ReferencesMap := make(map[string]string)
locus19_ReferencesMap["SNPedia.com - rs4986761"] = "https://www.snpedia.com/index.php/Rs4986761"
locus19_RiskWeightsMap := make(map[string]int)
locus19_RiskWeightsMap["T;T"] = 0
locus19_RiskWeightsMap["C;T"] = 1
locus19_RiskWeightsMap["T;C"] = 1
locus19_RiskWeightsMap["C;C"] = 2
locus19_OddsRatiosMap := make(map[string]float64)
locus19_OddsRatiosMap["T;T"] = 1
locus19_OddsRatiosMap["C;T"] = 1.05
locus19_OddsRatiosMap["T;C"] = 1.05
locus19_OddsRatiosMap["C;C"] = 1.51
locus19_BasePairProbabilitiesMap := make(map[string]float64)
locus19_BasePairProbabilitiesMap["T;T"] = .99
locus19_BasePairProbabilitiesMap["C;T"] = .01
locus19_BasePairProbabilitiesMap["T;C"] = .01
locus19_BasePairProbabilitiesMap["C;C"] = .001
locus19_Object := DiseaseLocus{
LocusIdentifier: "eedc23",
LocusRSID: 4986761,
RiskWeightsMap: locus19_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus19_OddsRatiosMap,
BasePairProbabilitiesMap: locus19_BasePairProbabilitiesMap,
References: locus19_ReferencesMap,
}
locusReferencesMap[4986761] = locus19_ReferencesMap
locus20_ReferencesMap := make(map[string]string)
locus20_ReferencesMap["SNPedia.com - rs3218695"] = "https://www.snpedia.com/index.php/Rs3218695"
locus20_RiskWeightsMap := make(map[string]int)
locus20_RiskWeightsMap["C;C"] = 0
locus20_RiskWeightsMap["C;A"] = 1
locus20_RiskWeightsMap["A;C"] = 1
locus20_RiskWeightsMap["A;A"] = 2
locus20_OddsRatiosMap := make(map[string]float64)
locus20_OddsRatiosMap["C;C"] = 1
locus20_OddsRatiosMap["C;A"] = 1.14
locus20_OddsRatiosMap["A;C"] = 1.14
locus20_OddsRatiosMap["A;A"] = 1.28
locus20_BasePairProbabilitiesMap := make(map[string]float64)
locus20_BasePairProbabilitiesMap["C;C"] = .98
locus20_BasePairProbabilitiesMap["C;A"] = .02
locus20_BasePairProbabilitiesMap["A;C"] = .02
locus20_BasePairProbabilitiesMap["A;A"] = .001
locus20_Object := DiseaseLocus{
LocusIdentifier: "2ee027",
LocusRSID: 3218695,
RiskWeightsMap: locus20_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus20_OddsRatiosMap,
BasePairProbabilitiesMap: locus20_BasePairProbabilitiesMap,
References: locus20_ReferencesMap,
}
locusReferencesMap[3218695] = locus20_ReferencesMap
locus21_ReferencesMap := make(map[string]string)
locus21_ReferencesMap["SNPedia.com - rs1800056"] = "https://www.snpedia.com/index.php/Rs1800056"
locus21_RiskWeightsMap := make(map[string]int)
locus21_RiskWeightsMap["T;T"] = 0
locus21_RiskWeightsMap["C;T"] = 1
locus21_RiskWeightsMap["T;C"] = 1
locus21_RiskWeightsMap["C;C"] = 2
locus21_OddsRatiosMap := make(map[string]float64)
locus21_OddsRatiosMap["T;T"] = 1
locus21_OddsRatiosMap["C;T"] = 1.05
locus21_OddsRatiosMap["T;C"] = 1.05
locus21_OddsRatiosMap["C;C"] = 1.51
locus21_BasePairProbabilitiesMap := make(map[string]float64)
locus21_BasePairProbabilitiesMap["T;T"] = .97
locus21_BasePairProbabilitiesMap["C;T"] = .03
locus21_BasePairProbabilitiesMap["T;C"] = .03
locus21_BasePairProbabilitiesMap["C;C"] = .001
locus21_Object := DiseaseLocus{
LocusIdentifier: "fc4bab",
LocusRSID: 1800056,
RiskWeightsMap: locus21_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus21_OddsRatiosMap,
BasePairProbabilitiesMap: locus21_BasePairProbabilitiesMap,
References: locus21_ReferencesMap,
}
locusReferencesMap[1800056] = locus21_ReferencesMap
locus22_ReferencesMap := make(map[string]string)
locus22_ReferencesMap["SNPedia.com - rs1800057"] = "https://www.snpedia.com/index.php/Rs1800057"
locus22_RiskWeightsMap := make(map[string]int)
locus22_RiskWeightsMap["C;C"] = 0
locus22_RiskWeightsMap["C;G"] = 1
locus22_RiskWeightsMap["G;C"] = 1
locus22_RiskWeightsMap["G;G"] = 2
locus22_OddsRatiosMap := make(map[string]float64)
locus22_OddsRatiosMap["C;C"] = 1
locus22_OddsRatiosMap["C;G"] = 1.05
locus22_OddsRatiosMap["G;C"] = 1.05
locus22_OddsRatiosMap["G;G"] = 1.51
locus22_BasePairProbabilitiesMap := make(map[string]float64)
locus22_BasePairProbabilitiesMap["C;C"] = .97
locus22_BasePairProbabilitiesMap["C;G"] = .03
locus22_BasePairProbabilitiesMap["G;C"] = .03
locus22_BasePairProbabilitiesMap["G;G"] = .001
locus22_Object := DiseaseLocus{
LocusIdentifier: "f8b225",
LocusRSID: 1800057,
RiskWeightsMap: locus22_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus22_OddsRatiosMap,
BasePairProbabilitiesMap: locus22_BasePairProbabilitiesMap,
References: locus22_ReferencesMap,
}
locusReferencesMap[1800057] = locus22_ReferencesMap
locus23_ReferencesMap := make(map[string]string)
locus23_ReferencesMap["SNPedia.com - rs3092856"] = "https://www.snpedia.com/index.php/Rs3092856"
locus23_RiskWeightsMap := make(map[string]int)
locus23_RiskWeightsMap["C;C"] = 0
locus23_RiskWeightsMap["C;T"] = 1
locus23_RiskWeightsMap["T;C"] = 1
locus23_RiskWeightsMap["T;T"] = 2
locus23_OddsRatiosMap := make(map[string]float64)
locus23_OddsRatiosMap["C;C"] = 1
locus23_OddsRatiosMap["C;T"] = 1.14
locus23_OddsRatiosMap["T;C"] = 1.14
locus23_OddsRatiosMap["T;T"] = 1.28
locus23_BasePairProbabilitiesMap := make(map[string]float64)
locus23_BasePairProbabilitiesMap["C;C"] = .95
locus23_BasePairProbabilitiesMap["C;T"] = .05
locus23_BasePairProbabilitiesMap["T;C"] = .05
locus23_BasePairProbabilitiesMap["T;T"] = .001
locus23_Object := DiseaseLocus{
LocusIdentifier: "4a072c",
LocusRSID: 3092856,
RiskWeightsMap: locus23_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus23_OddsRatiosMap,
BasePairProbabilitiesMap: locus23_BasePairProbabilitiesMap,
References: locus23_ReferencesMap,
}
locusReferencesMap[3092856] = locus23_ReferencesMap
locus24_ReferencesMap := make(map[string]string)
locus24_ReferencesMap["SNPedia.com - rs1800058"] = "https://www.snpedia.com/index.php/Rs1800058"
locus24_RiskWeightsMap := make(map[string]int)
locus24_RiskWeightsMap["C;C"] = 0
locus24_RiskWeightsMap["C;T"] = 1
locus24_RiskWeightsMap["T;C"] = 1
locus24_RiskWeightsMap["T;T"] = 2
locus24_OddsRatiosMap := make(map[string]float64)
locus24_OddsRatiosMap["C;C"] = 1
locus24_OddsRatiosMap["C;T"] = 1.05
locus24_OddsRatiosMap["T;C"] = 1.05
locus24_OddsRatiosMap["T;T"] = 1.51
locus24_BasePairProbabilitiesMap := make(map[string]float64)
locus24_BasePairProbabilitiesMap["C;C"] = .95
locus24_BasePairProbabilitiesMap["C;T"] = .04
locus24_BasePairProbabilitiesMap["T;C"] = .04
locus24_BasePairProbabilitiesMap["T;T"] = .01
locus24_Object := DiseaseLocus{
LocusIdentifier: "070f24",
LocusRSID: 1800058,
RiskWeightsMap: locus24_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus24_OddsRatiosMap,
BasePairProbabilitiesMap: locus24_BasePairProbabilitiesMap,
References: locus24_ReferencesMap,
}
locusReferencesMap[1800058] = locus24_ReferencesMap
locus25_ReferencesMap := make(map[string]string)
locus25_ReferencesMap["SNPedia.com - rs1801673"] = "https://www.snpedia.com/index.php/Rs1801673"
locus25_RiskWeightsMap := make(map[string]int)
locus25_RiskWeightsMap["A;A"] = 0
locus25_RiskWeightsMap["A;T"] = 1
locus25_RiskWeightsMap["T;A"] = 1
locus25_RiskWeightsMap["T;T"] = 2
locus25_OddsRatiosMap := make(map[string]float64)
locus25_OddsRatiosMap["A;A"] = 1
locus25_OddsRatiosMap["A;T"] = 1.14
locus25_OddsRatiosMap["T;A"] = 1.14
locus25_OddsRatiosMap["T;T"] = 1.28
locus25_BasePairProbabilitiesMap := make(map[string]float64)
locus25_BasePairProbabilitiesMap["A;A"] = .99
locus25_BasePairProbabilitiesMap["A;T"] = .01
locus25_BasePairProbabilitiesMap["T;A"] = .01
locus25_BasePairProbabilitiesMap["T;T"] = .001
locus25_Object := DiseaseLocus{
LocusIdentifier: "d08516",
LocusRSID: 1801673,
RiskWeightsMap: locus25_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus25_OddsRatiosMap,
BasePairProbabilitiesMap: locus25_BasePairProbabilitiesMap,
References: locus25_ReferencesMap,
}
locusReferencesMap[1801673] = locus25_ReferencesMap
locus26_ReferencesMap := make(map[string]string)
locus26_ReferencesMap["SNPedia.com - rs17879961"] = "https://www.snpedia.com/index.php/Rs17879961"
locus26_RiskWeightsMap := make(map[string]int)
locus26_RiskWeightsMap["A;A"] = 0
locus26_RiskWeightsMap["A;G"] = 1
locus26_RiskWeightsMap["G;A"] = 1
locus26_RiskWeightsMap["G;G"] = 2
locus26_OddsRatiosMap := make(map[string]float64)
locus26_OddsRatiosMap["A;A"] = 1
locus26_OddsRatiosMap["A;G"] = 1.14
locus26_OddsRatiosMap["G;A"] = 1.14
locus26_OddsRatiosMap["G;G"] = 1.28
locus26_BasePairProbabilitiesMap := make(map[string]float64)
locus26_BasePairProbabilitiesMap["A;A"] = .98
locus26_BasePairProbabilitiesMap["A;G"] = .02
locus26_BasePairProbabilitiesMap["G;A"] = .02
locus26_BasePairProbabilitiesMap["G;G"] = .001
locus26_Object := DiseaseLocus{
LocusIdentifier: "047b84",
LocusRSID: 17879961,
RiskWeightsMap: locus26_RiskWeightsMap,
MinimumRiskWeight: 0,
MaximumRiskWeight: 2,
OddsRatiosMap: locus26_OddsRatiosMap,
BasePairProbabilitiesMap: locus26_BasePairProbabilitiesMap,
References: locus26_ReferencesMap,
}
locusReferencesMap[17879961] = locus26_ReferencesMap
// TODO:
//-https://www.snpedia.com/index.php/Rs1042522
@ -883,7 +163,7 @@ func getBreastCancerDiseaseObject()PolygenicDisease{
//-https://www.snpedia.com/index.php/Rs7895676
//-https://www.snpedia.com/index.php/Rs140068132
breastCancerLociList := []DiseaseLocus{locus1_Object, locus2_Object, locus3_Object, locus4_Object, locus5_Object, locus6_Object, locus7_Object, locus8_Object, locus9_Object, locus10_Object, locus11_Object, locus12_Object, locus13_Object, locus14_Object, locus15_Object, locus16_Object, locus17_Object, locus18_Object, locus19_Object, locus20_Object, locus21_Object, locus22_Object, locus23_Object, locus24_Object, locus25_Object, locus26_Object}
breastCancerLociList := helpers.GetListOfMapKeys(locusReferencesMap)
referencesMap := make(map[string]string)
referencesMap["SNPedia.com - Breast Cancer"] = "https://www.snpedia.com/index.php/Breast_cancer"
@ -948,6 +228,7 @@ func getBreastCancerDiseaseObject()PolygenicDisease{
DiseaseName: "Breast Cancer",
EffectedSex: "Both",
DiseaseDescription: "Cancer growth in the tissue of a person's chest breast.",
LocusReferencesMap: locusReferencesMap,
LociList: breastCancerLociList,
GetAverageRiskProbabilitiesFunction: getAverageRiskProbabilitiesFunction,
References: referencesMap,

View file

@ -1,5 +1,5 @@
// polygenicDiseases provides information about polygenic diseases and the SNP base changes that effect a person's risk of becoming victim to them.
// polygenicDiseases provides information about polygenic diseases and the loci that influence them
package polygenicDiseases
@ -8,42 +8,8 @@ package polygenicDiseases
// Polygenic disease probabilities are less accurate, because individual base pair changes only cause comparatively small changes in the disease risk.
// Polygenic diseases are also more influenced by environmental factors, further decreasing risk accuracy.
//TODO: Eventually we want to use neural networks for polygenic disease prediction.
// This package is currently a less accurate solution until we get access to the necessary training data.
import "errors"
// DiseaseLocus is a location on a human genome that has an effect on the disease
type DiseaseLocus struct{
// 3 byte identifier, encoded in Hex.
LocusIdentifier string
// RSID that represents this locus
// If multiple RSIDs represent the same locus, use the first rsID for the locus in the locusMetadata package
LocusRSID int64
// Map Structure: Base pair -> Effect weight (Positive number = increased risk, negative number = decreased risk)
// The number only indicates a general effect of the base, for bases for which we do not have risk probability statistics
// 0 indicates that the base has no effect
RiskWeightsMap map[string]int
// Minimum and maximum values in above map
MinimumRiskWeight int
MaximumRiskWeight int
// Map Structure: Base Pair -> Odds ratio of BasePair/Normal (common) Base pair
// Number is greater than 1 = Increases risk, Number is less than 1 = decreases risk
// 1 indicates that the base has no impact
OddsRatiosMap map[string]float64
// Map Structure: Base Pair -> Probability that a person will have that base pair for the general population
BasePairProbabilitiesMap map[string]float64
// Map Structure: Reference name -> Reference link
References map[string]string
}
type PolygenicDisease struct{
@ -54,7 +20,14 @@ type PolygenicDisease struct{
// Is either "Mate"/"Female"/"Both"
EffectedSex string
LociList []DiseaseLocus
// This is a list of rsIDs which are known to have an effect on this disease
// We use these loci to predict trait outcomes with neural networks.
// Map Structure: rsID -> (map[Reference Name]Reference Link)
LocusReferencesMap map[int64]map[string]string
// This is a list of all loci used to predict this disease's risk
// This should be a list of the keys in LocusReferencesMap
LociList []int64
// Inputs:
// -string: "Mate"/"Female"
@ -64,10 +37,12 @@ type PolygenicDisease struct{
// -error
GetAverageRiskProbabilitiesFunction func(string, int)(float64, error)
// This map contains scientific resources about this disease
// Map Structure: Reference name -> Reference link
References map[string]string
}
var polygenicDiseaseNamesList []string
var polygenicDiseaseObjectsList []PolygenicDisease
@ -75,8 +50,9 @@ var polygenicDiseaseObjectsList []PolygenicDisease
func InitializePolygenicDiseaseVariables(){
breastCancerObject := getBreastCancerDiseaseObject()
autismObject := getAutismDiseaseObject()
polygenicDiseaseObjectsList = []PolygenicDisease{breastCancerObject}
polygenicDiseaseObjectsList = []PolygenicDisease{breastCancerObject, autismObject}
polygenicDiseaseNamesList = make([]string, 0, len(polygenicDiseaseObjectsList))
@ -94,7 +70,7 @@ func InitializePolygenicDiseaseVariables(){
func GetPolygenicDiseaseNamesList()([]string, error){
if (polygenicDiseaseNamesList == nil){
return nil, errors.New("GetDiseaseNamesList called when list is not initialized.")
return nil, errors.New("GetPolygenicDiseaseNamesList called when list is not initialized.")
}
return polygenicDiseaseNamesList, nil
@ -127,40 +103,3 @@ func GetPolygenicDiseaseObject(diseaseName string)(PolygenicDisease, error){
return PolygenicDisease{}, errors.New("GetPolygenicDiseaseObject called with unknown disease name: " + diseaseName)
}
//Outputs:
// -map[string]DiseaseLocus: Map of LocusIdentifier -> LocusObject
// -error (will return err if diseaseName is not found)
func GetPolygenicDiseaseLociMap(diseaseName string)(map[string]DiseaseLocus, error){
diseaseObject, err := GetPolygenicDiseaseObject(diseaseName)
if (err != nil) { return nil, err }
diseaseLociList := diseaseObject.LociList
diseaseLociMap := make(map[string]DiseaseLocus)
for _, locusObject := range diseaseLociList{
locusIdentifier := locusObject.LocusIdentifier
diseaseLociMap[locusIdentifier] = locusObject
}
return diseaseLociMap, nil
}
func GetPolygenicDiseaseLocusObject(diseaseName string, locusIdentifier string)(DiseaseLocus, error){
diseaseLociMap, err := GetPolygenicDiseaseLociMap(diseaseName)
if (err != nil){ return DiseaseLocus{}, err }
locusObject, exists := diseaseLociMap[locusIdentifier]
if (exists == false){
return DiseaseLocus{}, errors.New("GetDiseaseLocusObject called with unknown locus identifier: " + locusIdentifier)
}
return locusObject, nil
}

View file

@ -164,6 +164,7 @@ func getEyeColorTraitObject()Trait{
LociList_Rules: []int64{},
RulesList: []TraitRule{},
OutcomesList: []string{"Blue", "Green", "Hazel", "Brown"},
NumericValueFormatter: nil,
ReferencesMap: referencesMap,
}

View file

@ -142,6 +142,7 @@ func getFacialStructureTraitObject()Trait{
LociList_Rules: []int64{},
RulesList: []TraitRule{},
OutcomesList: []string{},
NumericValueFormatter: nil,
ReferencesMap: referencesMap,
}

View file

@ -62,6 +62,7 @@ func getHairColorTraitObject()Trait{
LociList_Rules: []int64{},
RulesList: []TraitRule{},
OutcomesList: []string{},
NumericValueFormatter: nil,
ReferencesMap: referencesMap,
}

View file

@ -245,6 +245,7 @@ func getHairTextureTraitObject()Trait{
LociList_Rules: lociList_Rules,
RulesList: hairTextureRulesList,
OutcomesList: outcomesList,
NumericValueFormatter: nil,
ReferencesMap: referencesMap,
}

View file

@ -1,11 +1,13 @@
package traits
import "seekia/internal/globalSettings"
import "seekia/internal/helpers"
import "maps"
import _ "embed"
import "errors"
import "encoding/gob"
import "bytes"
@ -50,6 +52,40 @@ func getHeightTraitObject()(Trait, error){
referencesMap := make(map[string]string)
referencesMap["GIANT consortium - Meta-analyses of Genome-Wide Association Studies - 2022 - Height"] = "https://portals.broadinstitute.org/collaboration/giant/index.php/GIANT_consortium_data_files"
numericValueFormatter := func(inputHeight float64, _ bool)(string, error){
getMyMetricOrImperial := func()(string, error){
exists, metricOrImperial, err := globalSettings.GetSetting("MetricOrImperial")
if (err != nil) { return "", err }
if (exists == false){
return "Metric", nil
}
if (metricOrImperial != "Metric" && metricOrImperial != "Imperial"){
return "", errors.New("Malformed globalSettings: Invalid metricOrImperial: " + metricOrImperial)
}
return metricOrImperial, nil
}
myMetricOrImperial, err := getMyMetricOrImperial()
if (err != nil){ return "", err }
if (myMetricOrImperial == "Metric"){
centimetersString := helpers.ConvertFloat64ToStringRounded(inputHeight, 2)
//TODO: Translate units
centimetersWithUnits := centimetersString + " centimeters"
return centimetersWithUnits, nil
}
feetInchesString, err := helpers.ConvertCentimetersToFeetInchesTranslatedString(inputHeight)
if (err != nil) { return "", err }
return feetInchesString, nil
}
heightObject := Trait{
TraitName: "Height",
TraitDescription: "The distance between the top of a standing person head and the floor.",
@ -59,6 +95,7 @@ func getHeightTraitObject()(Trait, error){
LociList_Rules: []int64{},
RulesList: []TraitRule{},
OutcomesList: []string{},
NumericValueFormatter: numericValueFormatter,
ReferencesMap: referencesMap,
}

View file

@ -0,0 +1,59 @@
package traits
import "seekia/internal/helpers"
import "maps"
func getHomosexualnessTraitObject()Trait{
// Map Structure: rsID -> References Map
locusReferencesMap := make(map[int64]map[string]string)
referencesMap_List1 := make(map[string]string)
referencesMap_List1["Large-scale GWAS reveals insights into the genetic architecture of same-sex sexual behavior"] = "https://www.science.org/doi/10.1126/science.aat7693"
lociList_1 := []int64{
10261857,
28371400,
34730029,
11114975,
}
for _, rsID := range lociList_1{
locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
}
homosexualnessLociList := helpers.GetListOfMapKeys(locusReferencesMap)
referencesMap := make(map[string]string)
referencesMap["Large-scale GWAS reveals insights into the genetic architecture of same-sex sexual behavior"] = "https://www.science.org/doi/10.1126/science.aat7693"
valueFormatter := func(inputHomosexualness float64, showUnits bool)(string, error){
inputHomosexualnessString := helpers.ConvertIntToString(int(inputHomosexualness))
if (showUnits == false){
return inputHomosexualnessString, nil
}
formattedValue := inputHomosexualnessString + "/10"
return formattedValue, nil
}
homosexualnessObject := Trait{
TraitName: "Homosexualness",
TraitDescription: "Feelings of sexual attraction towards people who belong to a person's own sex.",
DiscreteOrNumeric: "Numeric",
LocusReferencesMap: locusReferencesMap,
LociList: homosexualnessLociList,
LociList_Rules: []int64{},
RulesList: []TraitRule{},
OutcomesList: []string{},
NumericValueFormatter: valueFormatter,
ReferencesMap: referencesMap,
}
return homosexualnessObject
}

View file

@ -140,6 +140,7 @@ func getLactoseToleranceTraitObject()Trait{
LociList_Rules: lociList_Rules,
RulesList: lactoseToleranceRulesList,
OutcomesList: outcomesList,
NumericValueFormatter: nil,
ReferencesMap: referencesMap,
}

View file

@ -82,6 +82,7 @@ func getSkinColorTraitObject()Trait{
LociList_Rules: []int64{},
RulesList: []TraitRule{},
OutcomesList: []string{},
NumericValueFormatter: nil,
ReferencesMap: referencesMap,
}

View file

@ -43,6 +43,17 @@ type Trait struct{
// If the trait is Numeric, or their or no rules nor a neural network, then this list will be empty.
OutcomesList []string
// This function returns a formatted, translated representation of a numeric value for this trait
// For example, "150 centimeters", "5 foot 10 inches", "4/10"
// Inputs:
// -float64: The value to format
// -bool: Show "/10" units
// -The "/10" units are used for certain traits, where the unit value is not a real-world measurement (such as length, weight, etc.)
// -An example of an "/10" trait is Homosexuality, which is represented by a value between 0 and 10.
// -We don't want to "/10" if we are displaying a confidence range (Example: +/- 5.2)
// -If we did, then people would get confused by thinking the unit represents a fraction
NumericValueFormatter func(float64, bool)(string, error)
// This map contains scientific resources about this trait
// Map structure: Reference name -> Reference link
ReferencesMap map[string]string
@ -99,11 +110,13 @@ func InitializeTraitVariables()error{
eyeColorObject := getEyeColorTraitObject()
hairColorObject := getHairColorTraitObject()
skinColorObject := getSkinColorTraitObject()
homosexualnessObject := getHomosexualnessTraitObject()
heightObject, err := getHeightTraitObject()
if (err != nil){ return err }
traitObjectsList = []Trait{lactoseToleranceObject, hairTextureObject, facialStructureObject, eyeColorObject, hairColorObject, skinColorObject, heightObject}
traitObjectsList = []Trait{lactoseToleranceObject, hairTextureObject, facialStructureObject, eyeColorObject, hairColorObject, skinColorObject, heightObject, homosexualnessObject}
traitNamesList = make([]string, 0, len(traitObjectsList))
locusRSIDsMap = make(map[string]int64)

View file

@ -1,6 +1,6 @@
// createGeneticModels.go provides an interface to create genetic prediction models
// These are neural networks which predict traits such as eye color from raw genome files
// These are neural networks which predict attributes such as eye color and autism from raw genome files
// The OpenSNP.org dataset is used, and more datasets will be added in the future.
// You must download the dataset and extract it. The instructions are described in the utility.
// The trained models are saved in the /resources/geneticPredictionModels package for use in the Seekia app.
@ -16,6 +16,7 @@ import "fyne.io/fyne/v2/layout"
import "fyne.io/fyne/v2/dialog"
import "fyne.io/fyne/v2/data/binding"
import "seekia/resources/geneticReferences/polygenicDiseases"
import "seekia/resources/geneticReferences/traits"
import "seekia/resources/geneticReferences/locusMetadata"
@ -24,6 +25,7 @@ import "seekia/internal/genetics/locusValue"
import "seekia/internal/genetics/prepareRawGenomes"
import "seekia/internal/genetics/readRawGenomes"
import "seekia/internal/genetics/geneticPrediction"
import "seekia/internal/globalSettings"
import "seekia/internal/helpers"
import "seekia/internal/imagery"
import "seekia/internal/localFilesystem"
@ -46,12 +48,20 @@ import "time"
func main(){
polygenicDiseases.InitializePolygenicDiseaseVariables()
err := traits.InitializeTraitVariables()
if (err != nil){
panic(err)
return
}
err = globalSettings.InitializeGlobalSettingsDatastore()
if (err != nil){
panic(err)
return
}
app := app.New()
customTheme := getCustomFyneTheme()
@ -209,7 +219,7 @@ func setHomePage(window fyne.Window){
title := getBoldLabelCentered("Create Genetic Models Utility")
description1 := getLabelCentered("This utility is used to create the genetic prediction models.")
description2 := getLabelCentered("These models are used to predict traits such as eye color from raw genome files.")
description2 := getLabelCentered("These models are used to predict attributes such as eye color and autism from raw genome files.")
description3 := getLabelCentered("Seekia aims to have open source and reproducible genetic prediction technology.")
step1Label := getLabelCentered("Step 1:")
@ -722,16 +732,16 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
_, err = localFilesystem.CreateFolder("./TrainingData")
if (err != nil) { return false, false, err }
//TODO: Add more traits
traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"}
//TODO: Add more attributes
attributeNamesList := []string{"Eye Color", "Lactose Tolerance", "Height", "Autism", "Homosexualness"}
// We create the folders for each trait's training data
// We create the folders for each attribute's training data
for _, traitName := range traitNamesList{
for _, attributeName := range attributeNamesList{
traitNameWithoutWhitespace := strings.ReplaceAll(traitName, " ", "")
attributeNameWithoutWhitespace := strings.ReplaceAll(attributeName, " ", "")
folderpath := goFilepath.Join("./TrainingData/", traitNameWithoutWhitespace)
folderpath := goFilepath.Join("./TrainingData/", attributeNameWithoutWhitespace)
_, err = localFilesystem.CreateFolder(folderpath)
if (err != nil) { return false, false, err }
@ -891,13 +901,13 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
continue
}
for _, traitName := range traitNamesList{
for _, attributeName := range attributeNamesList{
traitNameWithoutWhitespace := strings.ReplaceAll(traitName, " ", "")
attributeNameWithoutWhitespace := strings.ReplaceAll(attributeName, " ", "")
trainingDataFolderpath := goFilepath.Join("./TrainingData", traitNameWithoutWhitespace)
trainingDataFolderpath := goFilepath.Join("./TrainingData", attributeNameWithoutWhitespace)
userDataExists, userTrainingDataList, err := geneticPrediction.CreateGeneticPredictionTrainingData_OpenSNP(traitName, userPhenotypeDataObject, userLociValuesMap)
userDataExists, userTrainingDataList, err := geneticPrediction.CreateGeneticPredictionTrainingData_OpenSNP(attributeName, userPhenotypeDataObject, userLociValuesMap)
if (err != nil) { return false, false, err }
if (userDataExists == false){
// User cannot be used for training
@ -991,35 +1001,35 @@ func setTrainModelsPage(window fyne.Window, previousPage func()){
description1 := getLabelCentered("Press the button below to begin training a genetic model.")
description2 := getLabelCentered("This will train a neural network using the user training data.")
description3 := getLabelCentered("This will take a while.")
description4 := getLabelCentered("You must select a trait model to train.")
description4 := getLabelCentered("You must select a model to train.")
traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"}
attributeNamesList := []string{"Eye Color", "Lactose Tolerance", "Height", "Autism", "Homosexualness"}
traitNameSelector := widget.NewSelect(traitNamesList, nil)
attributeNameSelector := widget.NewSelect(attributeNamesList, nil)
beginTrainingButton := getWidgetCentered(widget.NewButtonWithIcon("Begin Training Model", theme.MediaPlayIcon(), func(){
selectedTraitIndex := traitNameSelector.SelectedIndex()
if (selectedTraitIndex < 0){
title := "No Trait Selected"
dialogMessage1 := getLabelCentered("You must select a trait model to train.")
selectedAttributeIndex := attributeNameSelector.SelectedIndex()
if (selectedAttributeIndex < 0){
title := "No Attribute Selected"
dialogMessage1 := getLabelCentered("You must select an attribute model to train.")
dialogContent := container.NewVBox(dialogMessage1)
dialog.ShowCustom(title, "Close", dialogContent, window)
return
}
traitName := traitNameSelector.Selected
setStartAndMonitorTrainModelPage(window, traitName, currentPage)
attributeName := attributeNameSelector.Selected
setStartAndMonitorTrainModelPage(window, attributeName, currentPage)
}))
traitNameSelectorCentered := getWidgetCentered(traitNameSelector)
attributeNameSelectorCentered := getWidgetCentered(attributeNameSelector)
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), traitNameSelectorCentered, widget.NewSeparator(), beginTrainingButton)
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), attributeNameSelectorCentered, widget.NewSeparator(), beginTrainingButton)
window.SetContent(page)
}
func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, previousPage func()){
func setStartAndMonitorTrainModelPage(window fyne.Window, attributeName string, previousPage func()){
title := getBoldLabelCentered("Train Model")
@ -1154,7 +1164,7 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev
_, err := localFilesystem.CreateFolder("./TrainedModels")
if (err != nil) { return false, err }
trainingSetFilepathsList, _, err := getTrainingAndTestingDataFilepathLists(traitName)
trainingSetFilepathsList, _, err := getTrainingAndTestingDataFilepathLists(attributeName)
if (err != nil) { return false, err }
// Now we deterministically randomize the order of the trainingSetFilepathsList
@ -1165,7 +1175,7 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev
})
// We create a new neural network object to train
neuralNetworkObject, err := geneticPrediction.GetNewUntrainedNeuralNetworkObject(traitName)
neuralNetworkObject, err := geneticPrediction.GetNewUntrainedNeuralNetworkObject(attributeName)
if (err != nil) { return false, err }
// The number of rounds of training for the training data set
@ -1253,21 +1263,28 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev
return false, true, trainingDataObject, nil
}
traitObject, err := traits.GetTraitObject(traitName)
getAttributeIsNumericBool := func()(bool, error){
switch attributeName{
case "Height",
"Autism",
"Homosexualness":{
return true, nil
}
case "Lactose Tolerance",
"Eye Color":{
return false, nil
}
}
return false, errors.New("setStartAndMonitorTrainModelPage called with unknown attributeName: " + attributeName)
}
attributeIsNumeric, err := getAttributeIsNumericBool()
if (err != nil) { return false, err }
getTraitIsNumericBool := func()bool{
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric == "Numeric"){
return true
}
return false
}
traitIsNumeric := getTraitIsNumericBool()
processCompleted, err := geneticPrediction.TrainNeuralNetwork(traitName, traitIsNumeric, neuralNetworkObject, getNextTrainingDataFunction)
processCompleted, err := geneticPrediction.TrainNeuralNetwork(attributeName, attributeIsNumeric, neuralNetworkObject, getNextTrainingDataFunction)
if (err != nil) { return false, err }
if (processCompleted == false){
return false, nil
@ -1279,9 +1296,9 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev
neuralNetworkBytes, err := geneticPrediction.EncodeNeuralNetworkObjectToBytes(*neuralNetworkObject)
if (err != nil) { return false, err }
traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "")
attributeNameWithoutWhitespaces := strings.ReplaceAll(attributeName, " ", "")
neuralNetworkFilename := traitNameWithoutWhitespaces + "Model.gob"
neuralNetworkFilename := attributeNameWithoutWhitespaces + "Model.gob"
err = localFilesystem.CreateOrOverwriteFile(neuralNetworkBytes, "./TrainedModels/", neuralNetworkFilename)
if (err != nil) { return false, err }
@ -1343,36 +1360,36 @@ func setTestModelsPage(window fyne.Window, previousPage func()){
description3 := getLabelCentered("The testing data is not used to train the models.")
description4 := getLabelCentered("The results of the testing will be displayed at the end.")
description5 := getLabelCentered("The results will also be saved in the ModelAccuracies folder.")
description6 := getLabelCentered("You must select a trait model to test.")
description6 := getLabelCentered("You must select a model to test.")
traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"}
attributeNamesList := []string{"Eye Color", "Lactose Tolerance", "Height", "Autism", "Homosexualness"}
traitNameSelector := widget.NewSelect(traitNamesList, nil)
attributeNameSelector := widget.NewSelect(attributeNamesList, nil)
beginTestingButton := getWidgetCentered(widget.NewButtonWithIcon("Begin Testing Model", theme.MediaPlayIcon(), func(){
selectedTraitIndex := traitNameSelector.SelectedIndex()
if (selectedTraitIndex < 0){
title := "No Trait Selected"
dialogMessage1 := getLabelCentered("You must select a trait model to test.")
selectedAttributeIndex := attributeNameSelector.SelectedIndex()
if (selectedAttributeIndex < 0){
title := "No Attribute Selected"
dialogMessage1 := getLabelCentered("You must select a model to test.")
dialogContent := container.NewVBox(dialogMessage1)
dialog.ShowCustom(title, "Close", dialogContent, window)
return
}
traitName := traitNameSelector.Selected
attributeName := attributeNameSelector.Selected
setStartAndMonitorTestModelPage(window, traitName, currentPage)
setStartAndMonitorTestModelPage(window, attributeName, currentPage)
}))
traitNameSelectorCentered := getWidgetCentered(traitNameSelector)
attributeNameSelectorCentered := getWidgetCentered(attributeNameSelector)
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, widget.NewSeparator(), traitNameSelectorCentered, widget.NewSeparator(), beginTestingButton)
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, widget.NewSeparator(), attributeNameSelectorCentered, widget.NewSeparator(), beginTestingButton)
window.SetContent(page)
}
func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previousPage func()){
func setStartAndMonitorTestModelPage(window fyne.Window, attributeName string, previousPage func()){
title := getBoldLabelCentered("Testing Model")
@ -1409,17 +1426,35 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
window.SetContent(page)
testModelFunction := func(){
getAttributeIsNumericBool := func()(bool, error){
traitObject, err := traits.GetTraitObject(traitName)
switch attributeName{
case "Height",
"Autism",
"Homosexualness":{
return true, nil
}
case "Lactose Tolerance",
"Eye Color":{
return false, nil
}
}
return false, errors.New("setStartAndMonitorTrainModelPage called with unknown attributeName: " + attributeName)
}
attributeIsNumeric, err := getAttributeIsNumericBool()
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
setErrorEncounteredPage(window, errors.New("setStartAndMonitorTestModelPage called with unknown attributeName: " + attributeName), previousPage)
return
}
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (attributeIsNumeric == false){
if (traitIsDiscreteOrNumeric == "Discrete"){
// attribute is a Discrete trait
testModelFunction := func(){
//Outputs:
// -bool: Process completed (true == was not stopped mid-way)
@ -1448,10 +1483,10 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
traitPredictionInfoMap := make(map[geneticPrediction.DiscreteTraitOutcomeInfo]TraitAccuracyStatisticsValue)
_, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(traitName)
_, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(attributeName)
if (err != nil) { return false, nil, err }
traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "")
traitNameWithoutWhitespaces := strings.ReplaceAll(attributeName, " ", "")
// We read the trained model for this trait
modelFilename := traitNameWithoutWhitespaces + "Model.gob"
@ -1504,10 +1539,10 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
return false, nil, errors.New("Neural network prediction output length does not match expected output length.")
}
correctOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(traitName, true, trainingDataExpectedOutputLayer)
correctOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(attributeName, true, trainingDataExpectedOutputLayer)
if (err != nil) { return false, nil, err }
predictedOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(traitName, true, predictionLayer)
predictedOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(attributeName, true, predictionLayer)
if (err != nil) { return false, nil, err }
getPredictionIsCorrectBool := func()bool{
@ -1674,30 +1709,37 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
return
}
setViewModelTestingDiscreteTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage)
setViewModelTestingDiscreteTraitResultsPage(window, attributeName, traitPredictionAccuracyInfoMap, previousPage)
}
go testModelFunction()
return
} else {
// traitIsDiscreteOrNumeric == "Numeric"
// attribute is Numeric
testModelFunction := func(){
//Outputs:
// -bool: Process completed (true == was not stopped mid-way)
// -geneticPrediction.NumericTraitPredictionAccuracyInfoMap
// -geneticPrediction.NumericAttributePredictionAccuracyInfoMap
// -error
testModel := func()(bool, geneticPrediction.NumericTraitPredictionAccuracyInfoMap, error){
testModel := func()(bool, geneticPrediction.NumericAttributePredictionAccuracyInfoMap, error){
// We use this map to count up the information about predictions
// We use information from this map to construct the final accuracy information map
// Map Structure: NumericTraitPredictionInfo -> []float64 (List of distances for each prediction)
traitPredictionInfoMap := make(map[geneticPrediction.NumericTraitPredictionInfo][]float64)
// Map Structure: NumericAttributePredictionInfo -> []float64 (List of distances for each prediction)
attributePredictionInfoMap := make(map[geneticPrediction.NumericAttributePredictionInfo][]float64)
_, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(traitName)
_, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(attributeName)
if (err != nil) { return false, nil, err }
traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "")
attributeNameWithoutWhitespaces := strings.ReplaceAll(attributeName, " ", "")
// We read the trained model for this trait
modelFilename := traitNameWithoutWhitespaces + "Model.gob"
// We read the trained model for this attribute
modelFilename := attributeNameWithoutWhitespaces + "Model.gob"
trainedModelFilepath := goFilepath.Join("./TrainedModels/", modelFilename)
@ -1749,10 +1791,10 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
return false, nil, errors.New("Neural network numeric prediction output layer length is not 1.")
}
correctOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(traitName, trainingDataExpectedOutputLayer)
correctOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(attributeName, trainingDataExpectedOutputLayer)
if (err != nil) { return false, nil, err }
predictedOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(traitName, predictionLayer)
predictedOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(attributeName, predictionLayer)
if (err != nil) { return false, nil, err }
numberOfKnownLoci, numberOfKnownAndPhasedLoci, numberOfLoci, err := geneticPrediction.GetLociInfoFromNetworkInputLayer(trainingDataInputLayer)
@ -1764,19 +1806,19 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
proportionOfPhasedLoci := float64(numberOfKnownAndPhasedLoci)/float64(numberOfKnownLoci)
percentageOfPhasedLoci := int(100*proportionOfPhasedLoci)
newNumericTraitPredictionInfo := geneticPrediction.NumericTraitPredictionInfo{
newNumericAttributePredictionInfo := geneticPrediction.NumericAttributePredictionInfo{
PercentageOfLociTested: percentageOfLociTested,
PercentageOfPhasedLoci: percentageOfPhasedLoci,
}
distanceFromCorrectValue := math.Abs(predictedOutcomeValue - correctOutcomeValue)
existingList, exists := traitPredictionInfoMap[newNumericTraitPredictionInfo]
existingList, exists := attributePredictionInfoMap[newNumericAttributePredictionInfo]
if (exists == false){
traitPredictionInfoMap[newNumericTraitPredictionInfo] = []float64{distanceFromCorrectValue}
attributePredictionInfoMap[newNumericAttributePredictionInfo] = []float64{distanceFromCorrectValue}
} else {
existingList = append(existingList, distanceFromCorrectValue)
traitPredictionInfoMap[newNumericTraitPredictionInfo] = existingList
attributePredictionInfoMap[newNumericAttributePredictionInfo] = existingList
}
exampleIndexString := helpers.ConvertIntToString(index+1)
@ -1789,20 +1831,20 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
progressPercentageBinding.Set(newProgressFloat64)
}
// Now we construct the TraitAccuracyInfoMap
// Now we construct the AttributeAccuracyInfoMap
// This map stores the accuracy for each QuantityOfKnownLoci/QuantityOfPhasedLoci
traitPredictionAccuracyInfoMap := make(map[geneticPrediction.NumericTraitPredictionInfo]geneticPrediction.NumericTraitPredictionAccuracyRangesMap)
attributePredictionAccuracyInfoMap := make(map[geneticPrediction.NumericAttributePredictionInfo]geneticPrediction.NumericAttributePredictionAccuracyRangesMap)
for traitPredictionInfo, predictionDistancesList := range traitPredictionInfoMap{
for attributePredictionInfo, predictionDistancesList := range attributePredictionInfoMap{
if (len(predictionDistancesList) == 0){
return false, nil, errors.New("traitPredictionInfoMap contains empty predictionDistancesList.")
return false, nil, errors.New("attributePredictionInfoMap contains empty predictionDistancesList.")
}
// Map Structure: Accuracy Percentage (AP) -> Amount needed to deviate from prediction
// for the value to be accurate (AP)% of the time
newNumericTraitPredictionAccuracyRangesMap := make(map[int]float64)
newNumericAttributePredictionAccuracyRangesMap := make(map[int]float64)
if (len(predictionDistancesList) < 5){
// We don't have enough data to create an accuracyRanges map.
@ -1825,7 +1867,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
continue
}
_, exists := newNumericTraitPredictionAccuracyRangesMap[percentageOfPredictionsWithinDistance]
_, exists := newNumericAttributePredictionAccuracyRangesMap[percentageOfPredictionsWithinDistance]
if (exists == true){
// There exists a value for this percentage already
// This happens because we convert a float64 to an int
@ -1835,33 +1877,33 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
continue
}
newNumericTraitPredictionAccuracyRangesMap[percentageOfPredictionsWithinDistance] = distance
newNumericAttributePredictionAccuracyRangesMap[percentageOfPredictionsWithinDistance] = distance
}
traitPredictionAccuracyInfoMap[traitPredictionInfo] = newNumericTraitPredictionAccuracyRangesMap
attributePredictionAccuracyInfoMap[attributePredictionInfo] = newNumericAttributePredictionAccuracyRangesMap
}
// Testing is complete.
// We save the info map as a file in the ModelAccuracies folder
fileBytes, err := geneticPrediction.EncodeNumericTraitPredictionAccuracyInfoMapToBytes(traitPredictionAccuracyInfoMap)
fileBytes, err := geneticPrediction.EncodeNumericAttributePredictionAccuracyInfoMapToBytes(attributePredictionAccuracyInfoMap)
if (err != nil) { return false, nil, err }
_, err = localFilesystem.CreateFolder("./ModelAccuracies")
if (err != nil) { return false, nil, err }
modelAccuracyFilename := traitNameWithoutWhitespaces + "ModelAccuracy.gob"
modelAccuracyFilename := attributeNameWithoutWhitespaces + "ModelAccuracy.gob"
err = localFilesystem.CreateOrOverwriteFile(fileBytes, "./ModelAccuracies/", modelAccuracyFilename)
if (err != nil) { return false, nil, err }
progressPercentageBinding.Set(1)
return true, traitPredictionAccuracyInfoMap, nil
return true, attributePredictionAccuracyInfoMap, nil
}
processIsComplete, traitPredictionAccuracyInfoMap, err := testModel()
processIsComplete, attributePredictionAccuracyInfoMap, err := testModel()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
@ -1871,12 +1913,13 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
return
}
setViewModelTestingNumericTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage)
}
setViewModelTestingNumericAttributeResultsPage(window, attributeName, attributePredictionAccuracyInfoMap, previousPage)
return
}
go testModelFunction()
}
}
// This is a page to view the details of testing for a specific trait's model
func setViewModelTestingDiscreteTraitResultsPage(window fyne.Window, traitName string, traitAccuracyInfoMap geneticPrediction.DiscreteTraitPredictionAccuracyInfoMap, exitPage func()){
@ -2043,18 +2086,18 @@ func setViewModelTestingDiscreteTraitResultsPage(window fyne.Window, traitName s
}
// This is a page to view the details of testing for a specific trait's model
func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName string, traitAccuracyInfoMap geneticPrediction.NumericTraitPredictionAccuracyInfoMap, exitPage func()){
// This is a page to view the details of testing for a numeric attribute's model
func setViewModelTestingNumericAttributeResultsPage(window fyne.Window, attributeName string, attributeAccuracyInfoMap geneticPrediction.NumericAttributePredictionAccuracyInfoMap, exitPage func()){
title := getBoldLabelCentered("Numeric Trait Prediction Accuracy Details")
title := getBoldLabelCentered("Numeric Attribute Prediction Accuracy Details")
exitButton := getWidgetCentered(widget.NewButtonWithIcon("Exit", theme.CancelIcon(), exitPage))
description1 := getLabelCentered("The results of the prediction accuracy for this trait are below.")
description1 := getLabelCentered("The results of the prediction accuracy for this attribute are below.")
traitNameTitle := widget.NewLabel("Trait Name:")
traitNameLabel := getBoldLabel(traitName)
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameTitle, traitNameLabel, layout.NewSpacer())
attributeNameTitle := widget.NewLabel("Attribute Name:")
attributeNameLabel := getBoldLabel(attributeName)
attributeNameRow := container.NewHBox(layout.NewSpacer(), attributeNameTitle, attributeNameLabel, layout.NewSpacer())
description2 := getLabelCentered("Each value is a range that the prediction must be widened by to be accurate X% of the time.")
description3 := getLabelCentered("For example, for a height prediction to be accurate 90% of the time, allow a +/-10 cm range.")
@ -2078,13 +2121,40 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st
accuracyRangeColumn_34to66 := container.NewVBox(accuracyRangeTitle2, knownLociLabel_34to66, widget.NewSeparator())
accuracyRangeColumn_67to100 := container.NewVBox(accuracyRangeTitle3, knownLociLabel_67to100, widget.NewSeparator())
traitObject, err := traits.GetTraitObject(traitName)
// We get the formatter for the distance values
// This converts raw predictions to formatted values
// Example: 100 -> "100 centimeters"
getAttributeValueFormatter := func()(func(float64, bool)(string, error), error){
switch attributeName{
case "Homosexuality",
"Height":{
traitObject, err := traits.GetTraitObject(attributeName)
if (err != nil) { return nil, err }
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Numeric"){
return nil, errors.New("setViewModelTestingNumericTraitResultsPage called with non-discrete trait: " + traitName)
numericValueFormatter := traitObject.NumericValueFormatter
return numericValueFormatter, nil
}
}
// attribute is a polygenic disease
result := func(inputValue float64, _ bool)(string, error){
// Input value is a value between 0 and 10
inputValueFormatted := helpers.ConvertIntToString(int(inputValue))
return inputValueFormatted, nil
}
return result, nil
}
attributeValueFormatter, err := getAttributeValueFormatter()
if (err != nil){ return nil, err }
probabilityMinimumRange := 1
@ -2125,11 +2195,11 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st
predictionAccuracyDistancesSum_67to100 := float64(0)
distancesCount_67to100 := 0
for traitOutcomeInfo, traitPredictionAccuracyRangesMap := range traitAccuracyInfoMap{
for attributeOutcomeInfo, attributePredictionAccuracyRangesMap := range attributeAccuracyInfoMap{
percentageOfLociTested := traitOutcomeInfo.PercentageOfLociTested
percentageOfLociTested := attributeOutcomeInfo.PercentageOfLociTested
for percentageCorrect, distance := range traitPredictionAccuracyRangesMap{
for percentageCorrect, distance := range attributePredictionAccuracyRangesMap{
if (percentageCorrect < probabilityMinimumRange || percentageCorrect > probabilityMaximumRange){
continue
@ -2153,24 +2223,27 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st
}
}
getAverageAccuracyText := func(distancesSum float64, distancesCount int)string{
getAverageAccuracyText := func(distancesSum float64, distancesCount int)(string, error){
if (distancesCount == 0){
return "Unknown"
return "Unknown", nil
}
averageDistance := distancesSum/float64(distancesCount)
averageDistanceString := helpers.ConvertFloat64ToStringRounded(averageDistance, 1)
averageDistanceFormatted, err := attributeValueFormatter(averageDistance, false)
if (err != nil) { return "", err }
//TODO: Retrieve units from traits package?
result := "+/- " + averageDistanceString + " centimeters"
result := "+/- " + averageDistanceFormatted
return result
return result, nil
}
averageDistanceText_0to33 := getAverageAccuracyText(predictionAccuracyDistancesSum_0to33, distancesCount_0to33)
averageDistanceText_34to66 := getAverageAccuracyText(predictionAccuracyDistancesSum_34to66, distancesCount_34to66)
averageDistanceText_67to100 := getAverageAccuracyText(predictionAccuracyDistancesSum_67to100, distancesCount_67to100)
averageDistanceText_0to33, err := getAverageAccuracyText(predictionAccuracyDistancesSum_0to33, distancesCount_0to33)
if (err != nil){ return nil, err }
averageDistanceText_34to66, err := getAverageAccuracyText(predictionAccuracyDistancesSum_34to66, distancesCount_34to66)
if (err != nil){ return nil, err }
averageDistanceText_67to100, err := getAverageAccuracyText(predictionAccuracyDistancesSum_67to100, distancesCount_67to100)
if (err != nil){ return nil, err }
averageDistanceLabel_0to33 := getBoldLabelCentered(averageDistanceText_0to33)
averageDistanceLabel_34to66 := getBoldLabelCentered(averageDistanceText_34to66)
@ -2204,7 +2277,7 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st
return
}
page := container.NewVBox(title, exitButton, widget.NewSeparator(), description1, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), description2, description3, widget.NewSeparator(), resultsGrid)
page := container.NewVBox(title, exitButton, widget.NewSeparator(), description1, widget.NewSeparator(), attributeNameRow, widget.NewSeparator(), description2, description3, widget.NewSeparator(), resultsGrid)
pageScrollable := container.NewVScroll(page)
@ -2212,20 +2285,16 @@ func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName st
}
// This function returns a list of training data and testing data filepaths for a trait.
// This function returns a list of training data and testing data filepaths for an attribute.
//Outputs:
// -[]string: Sorted list of training data filepaths
// -[]string: Unsorted list of testing data filepaths
// -error
func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string, error){
func getTrainingAndTestingDataFilepathLists(attributeName string)([]string, []string, error){
if (traitName != "Eye Color" && traitName != "Lactose Tolerance" && traitName != "Height"){
return nil, nil, errors.New("getTrainingAndTestingDataFilepathLists called with invalid traitName: " + traitName)
}
attributeNameWithoutWhitespaces := strings.ReplaceAll(attributeName, " ", "")
traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "")
trainingDataFolderpath := goFilepath.Join("./TrainingData/", traitNameWithoutWhitespaces)
trainingDataFolderpath := goFilepath.Join("./TrainingData/", attributeNameWithoutWhitespaces)
filesList, err := os.ReadDir(trainingDataFolderpath)
if (err != nil) { return nil, nil, err }
@ -2238,7 +2307,7 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string
filepathIsFolder := filesystemObject.IsDir()
if (filepathIsFolder == true){
// Folder is corrupt
return nil, nil, errors.New("Training data is corrupt for trait: " + traitName)
return nil, nil, errors.New("Training data is corrupt for attribute: " + attributeName)
}
fileName := filesystemObject.Name()
@ -2249,24 +2318,32 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string
numberOfTrainingDataFiles := len(trainingDataFilenamesMap)
if (numberOfTrainingDataFiles == 0){
return nil, nil, errors.New("No training data exists for trait: " + traitName)
return nil, nil, errors.New("No training data exists for attribute: " + attributeName)
}
getNumberOfExpectedTrainingDatas := func()(int, error){
if (traitName == "Eye Color"){
switch attributeName{
return 113648, nil
} else if (traitName == "Lactose Tolerance"){
case "Eye Color":{
return 149894, nil
}
case "Lactose Tolerance":{
return 24872, nil
} else if (traitName == "Height"){
}
case "Height":{
return 92281, nil
}
case "Autism":{
return 32118, nil
}
case "Homosexualness":{
return 14500, nil
}
}
return 0, errors.New("Unknown traitName: " + traitName)
return 0, errors.New("Unknown attributeName: " + attributeName)
}
numberOfExpectedTrainingDatas, err := getNumberOfExpectedTrainingDatas()
@ -2276,7 +2353,7 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string
numberOfTrainingDataFilesString := helpers.ConvertIntToString(numberOfTrainingDataFiles)
return nil, nil, errors.New(traitName + " quantity of training datas is unexpected: " + numberOfTrainingDataFilesString)
return nil, nil, errors.New(attributeName + " quantity of training datas is unexpected: " + numberOfTrainingDataFilesString)
}
// We sort the training data to be in a deterministically random order
@ -2331,7 +2408,7 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string
numberOfUsers := len(userIdentifiersList)
if (numberOfUsers < 250){
return nil, nil, errors.New("Too few training data examples for trait: " + traitName)
return nil, nil, errors.New("Too few training data examples for attribute: " + attributeName)
}
// We use 200 users for testing (validation), so we don't train using them