<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Experiment objects filters - the rationale
A common transformation on experiment objects are those that apply some sort of filtering of subsetting of data. A syntactic sugar API is thus provided for the various common filtering operations on
the components of the experiment objects (for example the three dataframes of the MicrobiomeExperiment object).
The rationale behind providing such syntactic sugar in the API is that working with three dataframes at the same time can be taxing.
Again, rapid analysis and economy in typing, enabling quick workflow from one step to the next, are the ultimate aspirations here, avoiding repetitive boilerplate, especially knowing that almost the same operations are required in particular downstream analyses in various typical omic experiments.
This notebook/chapter will provide various examples (currently for MicrobiomeExperiment), and can be regarded as a cookbook for various operations performed in a microbial amplicon metabarcoding experiment.
Step1:  Experiment filters
A filter applied to a experiment/dataset is basically a sort of Transform. The Filter class itself inherits from Transform class.
As such, filters are applied as other transforms, using the apply and dapply methods.
The filter subpackage
From the transforms.filters subpackage, you can import the various filters
Step2:  Sample Filter examples
Step3:  An example of method chaining using efilter instead of filter
Step4:  Taxonomy filters
Taxonomy filters allows common operations done on the taxonomy metadata of the Observations/OTUs.
<ASSISTANT_TASK:>
Python Code:
%load_ext autoreload
%autoreload 2
#Load our data
from omicexperiment.experiment.microbiome import MicrobiomeExperiment
mapping = "example_map.tsv"
biom = "example_fungal.biom"
tax = "blast_tax_assignments.txt"
exp = MicrobiomeExperiment(biom, mapping,tax)
Explanation: Experiment objects filters - the rationale
A common transformation on experiment objects are those that apply some sort of filtering of subsetting of data. A syntactic sugar API is thus provided for the various common filtering operations on
the components of the experiment objects (for example the three dataframes of the MicrobiomeExperiment object).
The rationale behind providing such syntactic sugar in the API is that working with three dataframes at the same time can be taxing.
Again, rapid analysis and economy in typing, enabling quick workflow from one step to the next, are the ultimate aspirations here, avoiding repetitive boilerplate, especially knowing that almost the same operations are required in particular downstream analyses in various typical omic experiments.
This notebook/chapter will provide various examples (currently for MicrobiomeExperiment), and can be regarded as a cookbook for various operations performed in a microbial amplicon metabarcoding experiment.
End of explanation
exp.data_df
exp.mapping_df
Explanation: Experiment filters
A filter applied to a experiment/dataset is basically a sort of Transform. The Filter class itself inherits from Transform class.
As such, filters are applied as other transforms, using the apply and dapply methods.
The filter subpackage
From the transforms.filters subpackage, you can import the various filters:
from omicexperiment.transforms.filters import Sample
from omicexperiment.transforms.filters import Observation 
from omicexperiment.transforms.filters import Taxonomy
These "filters" are also provided on the MicrobiomeExperiment object, as shortcuts. However, I am still considering a better interface to filters so I am re-considering this particular API.
Taxonomy = exp.Taxonomy
#OR
from omicexperiment.transforms.filters import Taxonomy
What are filters?
Filters are subclasses of the Filter class. Filters can be considered fairly magical, as they utilize operator overloading in an attempt to provide a shorthand API with a sugary syntax for applying various filtering on the experiment dataframe objects.
The three filters 
* Taxonomy filter: apply various operations on the taxonomy
* Sample filter: apply various operations on samples/sample metadata
* Observation filter: apply various operations on observations (i.e. OTUs in a microbiome context)
The only way to get the gist of how these work is perhaps to view the code examples.
End of explanation
Sample = exp.Sample
#OR
from omicexperiment.transforms.filters import Sample
#1. the count filter
exp.dapply(Sample.count > 90000) #note sample0 was filtered off as its count is = 86870
#note the use of the operator overloading here so that the expression equals to
#a new Filter instance that holds this information 
#if you have worked with SQLAlchemy ORM, a very similar technique is used by sqlalchemy filters
(Sample.count > 90000)
#the count filter actually implements other operators as well (due to the FlexibleOperator mixin)
#here we try the __eq__ (==) operator, the cell above we tried the > operator
exp.dapply(Sample.count == 100428)
#it only selected the sample with exact count of 100428
#2. the att (attribute) filter
#   this filters on the "attributes" (i.e. metadata) of the samples
#   present in the mapping dataframe
#   this uses an attribute access (dotted) syntax
#here we only select samples in the 'control' group
exp.dapply(Sample.att.group == 'control') #only one sample in this group
(Sample.att.group == 'control')
#select only samples of asthmatic patients
exp.dapply(Sample.att.asthma == 1) #only three asthma-positive samples
#another alias for the att filter is the c attribute on the Sample Filter
#(c is short for "column", as per sqlalchemy convention)
exp.dapply(Sample.c.asthma == 1) #only three asthma-positive samples
#some columns may not be legal python attribute names,
#so for these we allow the [] (__getitem__) syntax
exp.dapply(Sample.att['#SampleID'] == 'sample0')
Explanation: Sample Filter examples
End of explanation
exp.apply(Sample.c.asthma == 1).dapply(Sample.count > 100000) #two samples
# the Sample groupby Transform
#the aggregate function here is the mean,
exp.dapply(Sample.groupby("group"))
# we can also change the aggfunc from mean to sum
import numpy as np
exp.dapply(Sample.groupby("group", aggfunc=np.sum))
Explanation: An example of method chaining using efilter instead of filter
End of explanation
Taxonomy = exp.Taxonomy #OR from omicexperiment.transforms.filters import Taxonomy
exp.taxonomy_df
'''
We noticed above that one of the assignments was identified at a highest
resolution only at the family level.
We can utilize the taxonomy attribute filters to remove these OTUs that
were classified at a lower resolution than a genus. 
'''
genus_or_higher = exp.apply(Taxonomy.rank_resolution >= 'genus')
genus_or_higher.data_df
#The TaxonomyGroupBy Transform
genus_or_higher.apply(Taxonomy.groupby('genus')).data_df
#the Taxonomy.groupby is a shortcut for the TaxonomyGroupBy transform in the transforms.taxonomy module.
#Another example of the various Taxonomy attribute filters
exp.dapply(Taxonomy.genus == 'g__Aspergillus')
#only three otus had a genus assigned as 'g__Aspergillus"
Explanation: Taxonomy filters
Taxonomy filters allows common operations done on the taxonomy metadata of the Observations/OTUs.
End of explanation
<END_TASK>