关于kmer https://en.wikipedia.org/wiki/K-mer
我试图在一个大的fastq文件中找到最常见的k-mers。我的计划是使用misra-gries算法找到最常见的k-mers,然后用第二遍搜索文件中的每个频繁k-mer的计数。但我认为我的算法不够高效。这是我的下面的第一稿。我尽量保持内存效率。(程序不能耗尽内存)
我也发现了这个DSK算法,但是这个算法对我来说太难理解而没有看到简单的实现。 http://minia.genouest.org/dsk/
注意:每个计数器的ID也是整数而不是字符串,我将在我的最终草稿中稍后更改。
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
struct node {
string id;
int count;
};
void searchCount(vector <node>&memory, string line,int k) {
int count = 0;
string kMer;
for (int i = 0; i < memory.size(); i++) {
if (memory[i].id != "") {
for (int j = 0; j < line.length() - k + 1; j++) {
kMer = line.substr(j, k);
if (kMer == memory[i].id) {
count++;
}
}
}
memory[i].count = count;
count = 0;
}
}
int doWeHaveSpace(vector <node> memory) {
for (int i = 0; i < memory.size(); i++) {
if (memory[i].id == "") {
return i;
}
}
return -1;
}
void MisraGries(string element, vector <node> &memory) {
bool isHere = false;
int index;
for (int i = 0; i < memory.size(); i++) {
if (memory[i].id == element) {
isHere = true;
index = i;
}
}
if (isHere) {
memory[index].count++;
}
else {
int freeIndex = doWeHaveSpace(memory);
if (freeIndex+1) {
memory[freeIndex].count++;
memory[freeIndex].id = element;
}
else {
for (int i = 0; i < memory.size(); i++) {
if (memory[i].count != 0) {
memory[i].count--;
if (memory[i].count == 0) {
memory[i].id = "";
}
}
}
}
}
}
void filecheck(ifstream & input, string prompt) // this function checks and opens input files
{
string filename;
cout << "Please enter file directory and name for " << prompt << ": ";
do
{
getline(cin, filename);
input.open(filename.c_str());
if (input.fail())
cout << " wrong file directory. Please enter real directory. ";
} while (input.fail());
}
int main() {
int line = 1;
string filename;
ifstream input;
ofstream output;
string search;
vector <node> frequent(1000);
for (int i = 0; i < frequent.size(); i++) {
frequent[i].id = "";
frequent[i].count = 0;
}
int k = 30;
string kMer;
filecheck(input, "input file");
while (!input.eof())
{
getline(input, search); // it gets infos line by line to count lines
line++;
if (line == 3) {
for (int i = 0; i < search.length() - k + 1; i++) {
kMer = search.substr(i, k);
MisraGries(kMer, frequent);
}
line = -1;
}
}
return 0;
}
答案 0 :(得分:1)
您可以通过将最常用的k-mers存储在哈希表而不是数组中来加速代码。通过这种方式,您可以在O(1)
时间内处理一个k-mer(假设长度是常数),如果它已经在缓存中(如果它不在,它仍然需要线性传球,但平均可能会有很大的提升。
如果通过在某种辅助数据结构(如优先级队列)中保留其他信息而导致很多未命中,您也可以使其更快,以便您可以找到count = 0
的元素并删除它们而不检查所有其他元素。
考虑到k
在您的示例中非常小,您可以增加内存缓存的大小(典型的计算机应该很容易在内存中保留数百万个这样的字符串),以便&# 39;重新减少错过。
您可以在第一次传递期间通过哈希k-mers存储更多数据(这样,您只需要将整数存储在内存而不是字符串中)。
总结一下,我建议将缓存设置得更大(只要它适合内存)并使用更合适的数据结构来支持快速查找,例如哈希表(std::unordered_map
在C ++)。