This workshop is still framed around familiarizing you with basic bioinformatics skills and data formats. Some of the exact examples we use may be suited for LLMs, but the skills learned are still important.
To start, on this page, we thought we'd introduce some of the most basic validation skills that are important to honing your intuition and technical skills. For simplicity, we assume the data format here is a generic tab-delimited text file, except where otherwise noted. Many bioinformatics file formats are indeed this.
In a basic table, the first row is often headers. However, for standardized file formats headers may not be included since they should be the same across
all files. Additionally, bioinformatics files often include metadata, provenance, and other information in the first few rows of a file. These are often
denoted with a # at the start of the line. It is important to know if your file has headers, because they will affect how
you read the file and should be skipped for any validation or analysis of the data.
Here is a simple way to check if a file has headers with the head command:
head [my-data-file].tabClick to see command breakdown
| Command line parameter | Description |
|---|---|
| head | A Linux command that prints the first few lines of a file to the screen. |
| [my-data-file].tab | The name of the file you want to view the first lines of. |
This should print some text to the screen: the beginning few rows of the file. If all you see are data values, then the file does not have headers (and you should hopefully be able to look up what the columns are). If the first row has text describing the columns, that is a header.
If there are multiple metadate lines beginning with #, you will want to count them, for example like this:
grep "^#" [my-data-file].tab | wc -lClick to see command breakdown
| Command line parameter | Description |
|---|---|
| grep | A Linux command searches for strings in each line of a file. |
| "^#" | The string to search for. In this case, "^" is a regular expression that says "match the beginning of the line" and "#" is the character to match. |
| [my-data-file].tab | The name of the file you want to search. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| wc | The Linux word count command. Counts the number of lines, words, and characters in an input file. |
| -l | Tells wc to only count number of lines. |
This will count the number of lines that start with a hash symbol, which are typically metadata lines in data files. You will have to remember or account for how many header lines are in your file going forward.
Exercise: What is one problem you could encounter when counting metadata headers in this way?
If you have an understanding of the data files and their contents, looking at the size of a file can give you an idea if something is wrong. For example, let's say you run your big experiment and send the samples off to the sequencing facility. They send you a link to download the files which you click and let run on your computer. You return to a completed download dialogue. However, you think you should make sure it was successful, so you check some of the FASTQ file sizes:
du -sh [my-data-file].fastqClick to see command breakdown
| Command line parameter | Description |
|---|---|
| du | A Linux command that prints the size of a file or directory. |
| -sh | Parameters for du to print the size in a human-readable format. |
| [my-data-file].fastq | The name of the file you want to check the size of. |
For 9 out of 10 of your samples, the command reports between 60GB and 70GB file sizes, but for one its only 35GB. This should be a red flag to you to stop and check the file more thoroughly. Is the genome of this sample expected to be smaller? How many reads are in the file? Was the download interrupted for the last sample (likely)? Maybe the sequencing facility made a mistake and sent the wrong file or sequenced the wrong sample.
In another scenario, perhaps you are processing some data and doing some filtering. How can you tell, at a glance, the extent of your filtering. Well, if the filtering works by removing data rows from your file, then you can count the rows in each:
wc -l [my-data-file].tabClick to see command breakdown
| Command line parameter | Description |
|---|---|
| wc | The Linux word count command. Counts the number of lines, words, and characters in an input file. |
| -l | Tells wc to only count number of lines. |
| [my-data-file].tab | The name of the file you want to check the number of rows in. |
Let's say this prints 10000. Your file has 10000 rows. Then, you (or your favorite LLM) does the filtering task, and you can again count the number of lines in the filtered file:
wc -l [my-filtered-data-file].tabMaybe this prints 1000. Filtering removed 9000 rows. Are your filtering parameters too strict to be removing 90 percent of your data or is this expected? (Tweaking filtering criteria is a time-honored bioinformatics task.) Whether this is expected or not, you will have to report and justify this filtering when you communicate your results in talks or papers.
Another basic check would be to count duplicated rows in a file:
sort [my-data-file].tab | uniq -d | wc -lClick to see command breakdown
| Command line parameter | |
|---|---|
| sort | A Linux command that sorts the lines in a file. |
| [my-data-file].tab | The name of the file you want to sort. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| uniq | A Linux command that is used to find unique and duplicate lines in a file. |
| -d | Tells uniq to only print duplicate lines. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| wc | A Linux command that counts the number of lines, words, or characters in a file. |
| -l | Tells wc to only count number of lines. |
If the number displayed on the screen is 0, then there are no duplicated rows in the file. If it is greater than 0, then there are duplicated rows. You can pipe the output
to head instead of wc to see the first few duplicated rows.
Again, you will have to determine if the number of duplicated rows is expected or not, and if not, you will have to figure out how and when they were added to the file.
Oftentimes, one column of a data file will contain some sort of unique identifier that corresponds to sample, variant, or whatever the row represents. One good check is to count the number of these unique identifiers to match against your expectations.
For instance, perhaps you or an LLM has been processing the data through several steps and you decide its time to pause and do some sanity checks. You take your current file and note that the sample IDs are in the first column, so you want to know how many there are:
cut -f 1 [my-data-file].tab | sort | uniq | wc -lClick to see command breakdown
| Command line parameter | Description |
|---|---|
| cut | A Linux command that extracts specific columns from a file. |
| -f 1 | Tells cut to extract the first column. |
| [my-data-file].tab | The name of the file you want to extract the first column from. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| sort | A Linux command that sorts the lines in a file. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| uniq | A Linux command that is used to find unique and duplicate lines in a file. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| wc | A Linux command that counts the number of lines, words, or characters in a file. |
| -l | Tells wc to only count number of lines. |
You started out your experiment with 100 samples, but this command prints 99. Now again you have to stop and assess whether this is expected or not. Did one of your steps filter out "low quality" samples and this one didn't make it? Was it dropped erroneously? Or was this a conscious choice based on other experimental design factors?
In a data table, the symbol NA is often used to denote missing data. Do you expect NAs in your data? How many is too many for your experiment?
Count NAs in the third column of a data file like this:
cut -f 3 [my-data-file].tab | grep "NA" | wc -lClick to see command breakdown
| Command line parameter | Description |
|---|---|
| cut | A Linux command that extracts specific columns from a file. |
| -f 3 | Tells cut to extract the third column. |
| [my-data-file].tab | The name of the file you want to extract the third column from. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| grep | A Linux command searches for strings in each line of a file. |
| "NA" | The string to search for. In this case, "NA" is the string to match. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| wc | A Linux command that counts the number of lines, words, or characters in a file. |
| -l | Tells wc to only count number of lines. |
Or, count NAs in each column (assuming your file has 10 columns and skipping the first because it contains sample IDs):
for i in {2..10}; do echo -n "$i: "; cut -f$i [my-data-file].tab | grep -cx NA; doneClick to see command breakdown
| Command line parameter | Description |
|---|---|
| for i in {2..10}; do | A bash for loop that iterates over the numbers 2 through 10. |
| echo | A Linux command that prints a line of text to the terminal. |
| -n | Tells echo to not print a newline character at the end of the output. |
| "$i: " | Prints the current value of the loop variable i followed by a colon and a space. |
| cut | A Linux command that extracts sections from each line of a file. |
| -f$i | Tells cut to extract the i-th column, where i is the current value of the loop variable. |
| [my-data-file].tab | The name of the file you want to extract columns from. |
| | | The pipe character, telling the shell to use the output from the previous command as the input to the next command. |
| grep | A Linux command searches for strings in each line of a file. |
| -cx | Tells grep to count the number of lines that match the pattern exactly. |
| NA | The string to search for. In this case, "NA" is the string to match. |
| ; done | Indicates the end of the for loop. |
That's obviously a bit more complicated as it introduces a loop and other syntax. But learning these skills even a little bit can give you powerful abilities that, at the very least, allow you to check the LLMs work, or, at most, could allow you to do the work yourself faster.
