【发布时间】:2012-12-23 11:33:54
【问题描述】:
我正在尝试替换以空格分隔的大型文本文件中的值,但找不到针对此特定问题的合适答案:
假设我有一个文件“OLD_FILE”,其中包含一个标题和大约 200 万行:
COL1 COL2 COL3 COL4 COL5
rs10 7 92221824 C A
rs1000000 12 125456933 G A
rs10000010 4 21227772 T C
rs10000012 4 1347325 G C
rs10000013 4 36901464 C A
rs10000017 4 84997149 T C
rs1000002 3 185118462 T C
rs10000023 4 95952929 T G
...
我想使用一个大的(280 万行)转换表将每一行的第一个值替换为相应的值。在这个转换表中,第一列列出了我想要替换的值,第二列列出了相应的新值:
COL1_b36 COL2_b37
rs10 7_92383888
rs1000000 12_126890980
rs10000010 4_21618674
rs10000012 4_1357325
rs10000013 4_37225069
rs10000017 4_84778125
rs1000002 3_183635768
rs10000023 4_95733906
...
所需的输出将是一个文件,其中第一列中的所有值都已根据转换表进行了更改:
COL1 COL2 COL3 COL4 COL5
7_92383888 7 92221824 C A
12_126890980 12 125456933 G A
4_21618674 4 21227772 T C
4_1357325 4 1347325 G C
4_37225069 4 36901464 C A
4_84778125 4 84997149 T C
3_183635768 3 185118462 T C
4_95733906 4 95952929 T G
...
附加信息:
-
性能是个问题(以下命令大约需要一年时间:
同时阅读 a b;做 sed -i "s/\b$a\b/$b/g" OLD_FILE ;完成
- 替换前需要完全匹配
- 并非 OLD_FILE 中的每个值都可以在转换表中找到...
- ...但是每个可以替换的值都可以在转换表中找到。
非常感谢任何帮助。
【问题讨论】:
-
对转换表进行排序(如您事先所知)。将其拆分为您认为合理的尽可能多的小文件。然后解析输入文件,并根据第一个(或前两个,或...)字母在适当的拆分转换文件中搜索其转换。
-
另一种方法:在 perl 中,使用哈希表,以便每个可能转换的字符串(转换文件中的第一列)都是与其转换值对应的键。如果它保存在内存中,它会真的很快。
-
一种类似的方法是找到一种方法来唯一地“散列”conversion_file 的第一列,以便每个条目都有一个(并且只有一个)值。测试一下:一旦你有了一个散列函数,尝试每个条目并记下它的输出值。验证 ( cat | sort | uniq -c | sort -rn) 它是唯一的。一旦找到合适的哈希函数,您只需要每个哈希值 (hashvalue.txt) 包含一个包含转换字符串的文件。
-
这些都是非常有用的建议,虽然要开始工作需要更精细一些,这就是我更喜欢 awk-oneliner 的原因。
标签: bash unix awk sed large-data