phylotypy 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. phylotypy-0.2.0/LICENSE +21 -0
  2. phylotypy-0.2.0/PKG-INFO +144 -0
  3. phylotypy-0.2.0/README.md +123 -0
  4. phylotypy-0.2.0/pyproject.toml +39 -0
  5. phylotypy-0.2.0/setup.cfg +4 -0
  6. phylotypy-0.2.0/setup.py +30 -0
  7. phylotypy-0.2.0/src/phylotypy/__init__.py +4 -0
  8. phylotypy-0.2.0/src/phylotypy/bootstrap.py +105 -0
  9. phylotypy-0.2.0/src/phylotypy/classifier.py +217 -0
  10. phylotypy-0.2.0/src/phylotypy/classify_bootstraps/__init__.py +1 -0
  11. phylotypy-0.2.0/src/phylotypy/classify_bootstraps/classify_bootstraps.c +30328 -0
  12. phylotypy-0.2.0/src/phylotypy/classify_bootstraps/classify_bootstraps.pyx +77 -0
  13. phylotypy-0.2.0/src/phylotypy/cond_prob_c/__init__.py +0 -0
  14. phylotypy-0.2.0/src/phylotypy/cond_prob_c/cond_prob_cython.c +13010 -0
  15. phylotypy-0.2.0/src/phylotypy/cond_prob_c/cond_prob_cython.pyx +40 -0
  16. phylotypy-0.2.0/src/phylotypy/conditional_prob.py +220 -0
  17. phylotypy-0.2.0/src/phylotypy/get_kmer_db.py +145 -0
  18. phylotypy-0.2.0/src/phylotypy/kmers.py +443 -0
  19. phylotypy-0.2.0/src/phylotypy/results.py +34 -0
  20. phylotypy-0.2.0/src/phylotypy/training_data.py +114 -0
  21. phylotypy-0.2.0/src/phylotypy/utilities/__init__.py +1 -0
  22. phylotypy-0.2.0/src/phylotypy/utilities/read_fasta.py +106 -0
  23. phylotypy-0.2.0/src/phylotypy/utilities/utilities.py +187 -0
  24. phylotypy-0.2.0/src/phylotypy.egg-info/PKG-INFO +144 -0
  25. phylotypy-0.2.0/src/phylotypy.egg-info/SOURCES.txt +34 -0
  26. phylotypy-0.2.0/src/phylotypy.egg-info/dependency_links.txt +1 -0
  27. phylotypy-0.2.0/src/phylotypy.egg-info/requires.txt +11 -0
  28. phylotypy-0.2.0/src/phylotypy.egg-info/top_level.txt +1 -0
  29. phylotypy-0.2.0/tests/test_bootstrap.py +23 -0
  30. phylotypy-0.2.0/tests/test_classify.py +60 -0
  31. phylotypy-0.2.0/tests/test_classify_boostrap_cython.py +38 -0
  32. phylotypy-0.2.0/tests/test_conditional_prob.py +53 -0
  33. phylotypy-0.2.0/tests/test_kmers.py +357 -0
  34. phylotypy-0.2.0/tests/test_read_fasta.py +40 -0
  35. phylotypy-0.2.0/tests/test_training_data.py +28 -0
  36. phylotypy-0.2.0/tests/test_utilities.py +30 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Chad Saltikov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: phylotypy
3
+ Version: 0.2.0
4
+ Summary: Naive Bayes Classifier with Rust-accelerated taxonomy functions
5
+ Author-email: Chad Saltikov <saltikov@ucsc.edu>
6
+ License: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: setuptools
11
+ Requires-Dist: numpy~=2.1.3
12
+ Requires-Dist: numba~=0.61.0
13
+ Requires-Dist: pandas~=2.2.3
14
+ Requires-Dist: requests
15
+ Requires-Dist: pandarallel
16
+ Requires-Dist: jax
17
+ Requires-Dist: cython
18
+ Provides-Extra: test
19
+ Requires-Dist: pytest; extra == "test"
20
+ Dynamic: license-file
21
+
22
+ # phylotypy
23
+ Naive Bayesian Classifier for 16S rRNA gene sequence data
24
+
25
+ Porting Riffomonas's CodeClub R package, phylotypr to python: https://github.com/riffomonas/phylotypr
26
+
27
+ It's been a great challenge learning how to interpret the R code into Python with minimal use of extra libraries.
28
+
29
+ It's best to clone the repository. Run vigentte.py to see if everything works.
30
+
31
+ Training the model with the full reference database from RDP takes about 30 seconds on my MacBook Pro.
32
+
33
+ You can modify the vignette at the end to classify your own sequences. I've done this using DADA2's output files.
34
+
35
+ There's also [read_fasta.py](src/phylotypy/utilities/read_fasta.py) that lets you take a fasta file of DNA seqences and process them into a dataframe for runing this classifier.
36
+
37
+ I made a separate vignette, [vignette.py](vignette.py) on how to do this and classify 16S sequence data from QIIME, DADA2, or text files.
38
+
39
+ Thanks Riffomonas for the inspiration. Check out the videos on his Youtube channel https://youtube.com/playlist?list=PLmNrK_nkqBpIZlWa3yGEc2-wX7An2kpCL&si=LmHDV02K5_wb6C0j
40
+
41
+ ## How to install
42
+ ```
43
+ pip install git+https://github.com/csaltikov/phylotypy.git
44
+ ```
45
+ or if using uv (recommended) (<a href="https://docs.astral.sh/uv/getting-started/installation/">how to install uv</a>)
46
+ ```
47
+ uv pip install git+https://github.com/csaltikov/phylotypy.git
48
+ ```
49
+
50
+ ## How to get started:
51
+ First download the training data, RDP's trainset19072023, either from https://mothur.org/wiki/rdp_reference_files/
52
+ You can use the one in the [data](data/) directory called [rdp_16S_v19.dada2.fasta](data/rdp_16S_v19.dada2.fasta)
53
+
54
+ I processed the latest rdp reference data into a format that will work here and for DADA2.
55
+
56
+ The taxonomy string looks like this semicolon separated:
57
+ ```
58
+ Bacteria;Phylum;Class;Order;Family;Genus
59
+
60
+ for example:
61
+ >Bacteria;Pseudomonadota;Gammaproteobacteria;Enterobacterales;Enterobacteriaceae;Citrobacter
62
+ TAGAGTTTGATCCATGGCTCAGATTGAACGCTGGCGGCAGGCCTAACAC.....
63
+ ```
64
+
65
+ 1. Load the training data and sequences to be classified
66
+ ```
67
+ from pathlib import Path
68
+ from phylotypy import classifier, results, read_fasta
69
+
70
+ rdp = read_fasta.read_taxa_fasta("data/rdp_16S_v19.dada2.fasta")
71
+ moving_pics = read_fasta.read_taxa_fasta("data/dna_moving_pictures.fasta")
72
+ ```
73
+ 2. Create the classifier. We'll call it database
74
+ ```
75
+ database = classifier.make_classifier(rdp)
76
+ ```
77
+ 3. Classify the sequences
78
+ ```
79
+ classified = classifier.classify_sequences(moving_pics, database)
80
+ ```
81
+ 4. Format the output
82
+ ```
83
+ classified = results.summarize_predictions(classified)
84
+ print(classified.columns)
85
+ ```
86
+ Output:
87
+ ```
88
+ >>> Index(['id', 'sequence', 'classification', 'Kingdom', 'Phylum', 'Class',
89
+ 'Order', 'Family', 'Genus', 'observed', 'lineage'],
90
+ dtype='object')
91
+ ```
92
+ ```
93
+ print(classified["classification"].head())
94
+ ```
95
+ Output:
96
+ ```
97
+ 0 Bacteria(100);Bacteroidota(100);Bacteroidia(10...
98
+ 1 Bacteria(100);Pseudomonadota(100);Betaproteoba...
99
+ 2 Bacteria(100);Bacillota(100);Bacilli(100);Lact...
100
+ 3 Bacteria(100);Bacteroidota(100);Bacteroidia(10...
101
+ 4 Bacteria(100);Bacteroidota(100);Bacteroidia(10...
102
+ Name: classification, dtype: object
103
+ ```
104
+ Format the results using results.summarize_predictions() function.
105
+ The output is a pandas dataframe and can be saved to csv.
106
+ ```
107
+ from phylotypy import results
108
+ classified = results.summarize_predictions(classified)
109
+ print(classified.head())
110
+
111
+ classified.to_csv("classified_results.csv")
112
+
113
+ ```
114
+ ## Example classification output:
115
+ The taxonomic levels "Domain", "Phylum", "Class", "Order", "Family", "Genus" are separated by ";". The numbers in the () represent the confidence in the classificaiton. The default confidence is 80%.
116
+ ```
117
+ >>> Bacteria(100);Pseudomonadota(99);Alphaproteobacteria(99);Rhodospirillales(99);Acetobacteraceae(99);Roseomonas(83)
118
+
119
+ >>> Bacteria(99);Bacteroidota(97);Bacteroidia(93);Bacteroidales(93);Bacteroidales_unclassified(93);Bacteroidales_unclassified(93)
120
+
121
+ ```
122
+ ## Complete code block:
123
+ ```
124
+ from pathlib import Path
125
+ from phylotypy import classifier, results, read_fasta
126
+
127
+ rdp = read_fasta.read_taxa_fasta("data/rdp_16S_v19.dada2.fasta")
128
+ moving_pics = read_fasta.read_taxa_fasta("data/dna_moving_pictures.fasta")
129
+
130
+ database = classifier.make_classifier(rdp)
131
+
132
+ classified = classifier.classify_sequences(moving_pics, database)
133
+ classified = results.summarize_predictions(classified)
134
+ print(classified.head())
135
+ ```
136
+ ### Requirements
137
+ setuptools
138
+ numpy
139
+ numba
140
+ pandas
141
+ requests
142
+ pandarallel
143
+ jax
144
+ cython
@@ -0,0 +1,123 @@
1
+ # phylotypy
2
+ Naive Bayesian Classifier for 16S rRNA gene sequence data
3
+
4
+ Porting Riffomonas's CodeClub R package, phylotypr to python: https://github.com/riffomonas/phylotypr
5
+
6
+ It's been a great challenge learning how to interpret the R code into Python with minimal use of extra libraries.
7
+
8
+ It's best to clone the repository. Run vigentte.py to see if everything works.
9
+
10
+ Training the model with the full reference database from RDP takes about 30 seconds on my MacBook Pro.
11
+
12
+ You can modify the vignette at the end to classify your own sequences. I've done this using DADA2's output files.
13
+
14
+ There's also [read_fasta.py](src/phylotypy/utilities/read_fasta.py) that lets you take a fasta file of DNA seqences and process them into a dataframe for runing this classifier.
15
+
16
+ I made a separate vignette, [vignette.py](vignette.py) on how to do this and classify 16S sequence data from QIIME, DADA2, or text files.
17
+
18
+ Thanks Riffomonas for the inspiration. Check out the videos on his Youtube channel https://youtube.com/playlist?list=PLmNrK_nkqBpIZlWa3yGEc2-wX7An2kpCL&si=LmHDV02K5_wb6C0j
19
+
20
+ ## How to install
21
+ ```
22
+ pip install git+https://github.com/csaltikov/phylotypy.git
23
+ ```
24
+ or if using uv (recommended) (<a href="https://docs.astral.sh/uv/getting-started/installation/">how to install uv</a>)
25
+ ```
26
+ uv pip install git+https://github.com/csaltikov/phylotypy.git
27
+ ```
28
+
29
+ ## How to get started:
30
+ First download the training data, RDP's trainset19072023, either from https://mothur.org/wiki/rdp_reference_files/
31
+ You can use the one in the [data](data/) directory called [rdp_16S_v19.dada2.fasta](data/rdp_16S_v19.dada2.fasta)
32
+
33
+ I processed the latest rdp reference data into a format that will work here and for DADA2.
34
+
35
+ The taxonomy string looks like this semicolon separated:
36
+ ```
37
+ Bacteria;Phylum;Class;Order;Family;Genus
38
+
39
+ for example:
40
+ >Bacteria;Pseudomonadota;Gammaproteobacteria;Enterobacterales;Enterobacteriaceae;Citrobacter
41
+ TAGAGTTTGATCCATGGCTCAGATTGAACGCTGGCGGCAGGCCTAACAC.....
42
+ ```
43
+
44
+ 1. Load the training data and sequences to be classified
45
+ ```
46
+ from pathlib import Path
47
+ from phylotypy import classifier, results, read_fasta
48
+
49
+ rdp = read_fasta.read_taxa_fasta("data/rdp_16S_v19.dada2.fasta")
50
+ moving_pics = read_fasta.read_taxa_fasta("data/dna_moving_pictures.fasta")
51
+ ```
52
+ 2. Create the classifier. We'll call it database
53
+ ```
54
+ database = classifier.make_classifier(rdp)
55
+ ```
56
+ 3. Classify the sequences
57
+ ```
58
+ classified = classifier.classify_sequences(moving_pics, database)
59
+ ```
60
+ 4. Format the output
61
+ ```
62
+ classified = results.summarize_predictions(classified)
63
+ print(classified.columns)
64
+ ```
65
+ Output:
66
+ ```
67
+ >>> Index(['id', 'sequence', 'classification', 'Kingdom', 'Phylum', 'Class',
68
+ 'Order', 'Family', 'Genus', 'observed', 'lineage'],
69
+ dtype='object')
70
+ ```
71
+ ```
72
+ print(classified["classification"].head())
73
+ ```
74
+ Output:
75
+ ```
76
+ 0 Bacteria(100);Bacteroidota(100);Bacteroidia(10...
77
+ 1 Bacteria(100);Pseudomonadota(100);Betaproteoba...
78
+ 2 Bacteria(100);Bacillota(100);Bacilli(100);Lact...
79
+ 3 Bacteria(100);Bacteroidota(100);Bacteroidia(10...
80
+ 4 Bacteria(100);Bacteroidota(100);Bacteroidia(10...
81
+ Name: classification, dtype: object
82
+ ```
83
+ Format the results using results.summarize_predictions() function.
84
+ The output is a pandas dataframe and can be saved to csv.
85
+ ```
86
+ from phylotypy import results
87
+ classified = results.summarize_predictions(classified)
88
+ print(classified.head())
89
+
90
+ classified.to_csv("classified_results.csv")
91
+
92
+ ```
93
+ ## Example classification output:
94
+ The taxonomic levels "Domain", "Phylum", "Class", "Order", "Family", "Genus" are separated by ";". The numbers in the () represent the confidence in the classificaiton. The default confidence is 80%.
95
+ ```
96
+ >>> Bacteria(100);Pseudomonadota(99);Alphaproteobacteria(99);Rhodospirillales(99);Acetobacteraceae(99);Roseomonas(83)
97
+
98
+ >>> Bacteria(99);Bacteroidota(97);Bacteroidia(93);Bacteroidales(93);Bacteroidales_unclassified(93);Bacteroidales_unclassified(93)
99
+
100
+ ```
101
+ ## Complete code block:
102
+ ```
103
+ from pathlib import Path
104
+ from phylotypy import classifier, results, read_fasta
105
+
106
+ rdp = read_fasta.read_taxa_fasta("data/rdp_16S_v19.dada2.fasta")
107
+ moving_pics = read_fasta.read_taxa_fasta("data/dna_moving_pictures.fasta")
108
+
109
+ database = classifier.make_classifier(rdp)
110
+
111
+ classified = classifier.classify_sequences(moving_pics, database)
112
+ classified = results.summarize_predictions(classified)
113
+ print(classified.head())
114
+ ```
115
+ ### Requirements
116
+ setuptools
117
+ numpy
118
+ numba
119
+ pandas
120
+ requests
121
+ pandarallel
122
+ jax
123
+ cython
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools>=45", "wheel", "Cython>=0.29.21", "numpy"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [tool.cython]
6
+ language_level = "3"
7
+
8
+ [tool.setuptools]
9
+ include-package-data = true
10
+
11
+ [tool.setuptools.package-data]
12
+ "*" = ["*.pyx", "*.pxd"]
13
+
14
+ [project]
15
+ name = "phylotypy"
16
+ version = "0.2.0"
17
+ description = "Naive Bayes Classifier with Rust-accelerated taxonomy functions"
18
+ authors = [
19
+ {name = "Chad Saltikov", email = "saltikov@ucsc.edu"}
20
+ ]
21
+ license = {text = "MIT"}
22
+ readme = "README.md"
23
+ requires-python = ">=3.11"
24
+ dependencies = [
25
+ "setuptools",
26
+ "numpy~=2.1.3",
27
+ "numba~=0.61.0",
28
+ "pandas~=2.2.3",
29
+ "requests",
30
+ "pandarallel",
31
+ "jax",
32
+ "cython"
33
+ ]
34
+
35
+ [project.optional-dependencies]
36
+ test = [
37
+ "pytest",
38
+ ]
39
+
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,30 @@
1
+ from setuptools import setup, Extension, find_packages
2
+ from Cython.Build import cythonize
3
+ import numpy as np
4
+
5
+
6
+ extensions = [
7
+ Extension(
8
+ "phylotypy.classify_bootstraps.classify_bootstraps",
9
+ ["src/phylotypy/classify_bootstraps/classify_bootstraps.pyx"],
10
+ include_dirs=[np.get_include()],
11
+ ),
12
+ # New cond_prob_cython Cython extension
13
+ Extension(
14
+ "phylotypy.cond_prob_c.cond_prob_cython",
15
+ ["src/phylotypy/cond_prob_c/cond_prob_cython.pyx"],
16
+ include_dirs=[np.get_include()],
17
+ extra_compile_args=['-O3'],
18
+ define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]
19
+ )
20
+ ]
21
+
22
+ setup(
23
+ name="phylotypy",
24
+ package_dir={"": "src"},
25
+ packages=find_packages(where="src"),
26
+ ext_modules=cythonize(
27
+ extensions,
28
+ compiler_directives={'language_level': "3"},
29
+ annotate=True),
30
+ )
@@ -0,0 +1,4 @@
1
+ from .cond_prob_c import cond_prob_cython
2
+ from .classify_bootstraps import classify_bootstraps_cython
3
+ from .utilities import read_fasta
4
+ from .utilities import utilities
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env python3
2
+
3
+ ##
4
+ from collections import Counter
5
+ from functools import partial
6
+ from itertools import repeat
7
+ from pathlib import Path
8
+
9
+ import numpy as np
10
+ from numpy.typing import NDArray
11
+
12
+ from phylotypy import kmers, classifier
13
+ from phylotypy.utilities import read_fasta
14
+
15
+
16
+ ##
17
+ def bootstrap(arr: list | np.ndarray, divider: int = 8, num_bs: int = 100) -> NDArray:
18
+ bootstrap_fn = partial(bootstrap_kmers, arr, divider)
19
+ return np.array(list(map(lambda _: bootstrap_fn(), repeat(1, num_bs))))
20
+
21
+
22
+ def bootstrap_kmers(kmer_arr: np.array, kmer_size: int = 8):
23
+ """Performs a single bootstrap sampling on a kmers array"""
24
+ valid_kmers = kmer_arr[kmer_arr != -1]
25
+ num_removed_kmers = len(kmer_arr) - len(valid_kmers)
26
+ n_kmers = len(valid_kmers) + num_removed_kmers
27
+ return np.random.choice(valid_kmers, n_kmers // kmer_size, replace=True)
28
+
29
+
30
+ def split_taxa_arr(taxa_arr: np.ndarray) -> np.ndarray:
31
+ """
32
+ Split array of taxonomy strings into a 2D array where each row is a
33
+ sample and each column is a taxonomic level.
34
+ """
35
+ return np.array([taxa_str.split(";") for taxa_str in taxa_arr])
36
+
37
+
38
+ def bootstrap_consensus_helper(arr):
39
+ ids, scores = np.apply_along_axis(kmers.get_consensus, axis=0, arr=arr)
40
+ return ids, scores
41
+
42
+
43
+ def sort_by_indices_helper(values_to_sort, indices_array):
44
+ sorted_indices = np.argsort(indices_array)
45
+ return values_to_sort[sorted_indices]
46
+
47
+
48
+ ##
49
+ def bootstrap_consensus(classified_bs_kmers: np.ndarray, genera_names: np.ndarray):
50
+ """
51
+ Find consensus taxonomy from bootstrap samples.
52
+
53
+ Parameters:
54
+ classified_bs_kmers: 1D array of integers representing bootstrap samples
55
+ database: Database object containing genera_names mapping;
56
+ database = {conditional_prob:np.array
57
+ genera_idx mapping}
58
+
59
+ Returns:
60
+ Dictionary with taxonomy consensus and confidence values
61
+ """
62
+ # Convert the 1D array of ints (classified_bs_kmers) to taxonomy strings
63
+ # using genera_names 1D array
64
+ taxa = genera_names[classified_bs_kmers]
65
+
66
+ # Split into a 2D array of (100,6)
67
+ res = split_taxa_arr(taxa)
68
+ n_levels = res.shape[1]
69
+
70
+ taxa_consensus = np.empty(n_levels, dtype=object)
71
+ confidence_consensus = np.zeros(n_levels, dtype=int)
72
+
73
+ # Use Counter directly instead of apply_along_axis with custom function
74
+ for i in range(n_levels):
75
+ counter = Counter(res[:, i])
76
+ most_common = counter.most_common(1)[0] # Returns (taxon, count)
77
+ taxa_consensus[i] = most_common[0]
78
+ confidence_consensus[i] = most_common[1]
79
+
80
+ return dict(taxonomy=taxa_consensus, confidence=confidence_consensus)
81
+
82
+
83
+ ##
84
+ if __name__ == "__main__":
85
+ from time import perf_counter
86
+
87
+ path = Path(__file__).parent
88
+ rdp_small_fasta = path / "../../data/trainset19_072023_small_db.fasta"
89
+
90
+ moving_pics = read_fasta.read_taxa_fasta(path / "../../data/dna_moving_pictures.fasta")
91
+ rdp_df = read_fasta.read_taxa_fasta(rdp_small_fasta)
92
+
93
+ start = perf_counter()
94
+ database = classifier.make_classifier(rdp_df)
95
+ end = perf_counter()
96
+ print(f"Time taken: {(end - start):.2f}")
97
+
98
+ start = perf_counter()
99
+ database1 = kmers.build_kmer_database(rdp_df["sequence"], rdp_df["id"], verbose=True)
100
+ end = perf_counter()
101
+ print(f"Time taken: {(end - start):.2f}")
102
+
103
+ print(np.allclose(database.conditional_prob, database1.conditional_prob))
104
+ print(np.allclose(database.genera_idx, database1.genera_idx))
105
+ print(np.allclose(database.genera_names, database1.genera_names))