我想在桌子上做一些简单的数据库操作而不用费心去打扰数据库软件,例如,我可以使用GitHub的“filo”包来做类似“groupby”的功能。我想知道是否有类似的东西可以实现一些简单的“加入”功能?或者我可以用Python或Bash做到吗?具体来说,我有一个像这样的表:
Col5a2 NM_007737 chr1 - 45447828 45447829
Slc40a1 NM_016917 chr1 - 45870140 45870141
Gm3852 NM_001177356 chr1 - 45956809 45956810
Slc39a10 NM_172653 chr1 - 46798055 46798056
Obfc2a NM_028696 chr1 - 51422944 51422945
Myo1b NM_001161817,NM_010863 chr1 - 51860519 51860520
.
.
.
我有一个清单
Slc40a1
Myo1b
Col5a2
Obfc2a
.
.
.
我想从表中获取列表中的项目,以便我得到:
Slc39a10 NM_172653 chr1 - 46798055 46798056
Myo1b NM_001161817,NM_010863 chr1 - 51860519 51860520
Col5a2 NM_007737 chr1 - 45447828 45447829
Obfc2a NM_028696 chr1 - 51422944 51422945
.
.
.
答案 0 :(得分:3)
这是使用awk
的一种方式:
awk 'FNR==NR { a[$1]=$0; next } $1 in a { print a[$1] }' table list
或格式化:
awk 'FNR==NR { a[$1]=$0; next } $1 in a { print a[$1] }' table list | column -t
结果:
Slc40a1 NM_016917 chr1 - 45870140 45870141
Myo1b NM_001161817,NM_010863 chr1 - 51860519 51860520
Col5a2 NM_007737 chr1 - 45447828 45447829
Obfc2a NM_028696 chr1 - 51422944 51422945
说明:
'FNR == NR {...}'是一个条件,仅对参数列表中的第一个文件为真。
因此对于名为'table'的文件中的每一行,第一列($ 1)被添加到一个数组(称为'a')中,并为其分配整行的值($ 0)。 'next'然后跳到代码的其余部分并跳转到下一行输入,直到'table'文件中的所有行都被处理完毕。
'a'中的$ 1是另一个条件。
这是在询问'list'文件的第一列是否是数组中的键。如果是,则打印出我们刚刚存储在数组中的第一列的值(a [$ 1])。
答案 1 :(得分:3)
您确实可以使用两个标准的unix工具join(1)
和sort(1)
来实现这一目标:
$ join <(sort table) <(sort list)
Col5a2 NM_007737 chr1 - 45447828 45447829
Myo1b NM_001161817,NM_010863 chr1 - 51860519 51860520
Obfc2a NM_028696 chr1 - 51422944 51422945
Slc40a1 NM_016917 chr1 - 45870140 45870141
需要拨打sort
,因为(来自join man page):
重要说明:必须在连接字段上对FILE1和FILE2进行排序。例如,如果'join'没有选项,则使用'sort -k 1b,1'。注意,比较遵守'LC_COLLATE'指定的规则。如果输入未排序且某些行无法连接,则会给出警告消息。
更新:灵感来自this answer的解决方案,保持秩序:
$ join -1 2 <(cat -n list | sort -k2,2) <(sort table) | sort -nk2,2 | cut -d\ -f1,3-
答案 2 :(得分:1)
如果你只是在表的第一列进行非常简单的查找,那么python dict
可能就足够了。
像这样构建:
table = {}
with open(table_file) as f:
for line in f:
row = line.split()
table[row[0]] = row
然后,您可以使用列表理解对此词典进行“加入”:
results = [table[key] for key in keys_list]
或者,如果您的第二个列表也是数据文件,则可以改为:
with open(second_file) as f:
results = [table[line.strip] for line in f]
答案 3 :(得分:0)
import numpy as np
data = []
with open("file1.txt") as f: #the data file
for row in f:
data.append(row.split())
with open("file2.txt") as f: #the keys file
keys = map(str.strip,f.readlines())
np_data = np.array(data,np.str)
mask = np.in1d(np_data[:,0],keys)
print np_data[mask]
如果我真的不想使用数据库,那该怎么做呢
答案 4 :(得分:0)
您可以使用像数据库一样工作的pandas来“选择”和转动。这是一个有效的例子:
import pandas as pd
data = pd.DataFrame({
'Col5a2' : ['NM_007737', '-', 'chr1', 45447828, 45447829],
'Slc40a1' : ['NM_016917', '-', 'chr1', 45870140, 45870141],
'Gm3852' : ['NM_001177356', '-', 'chr1', 45956809, 45956810],
'Slc39a10': ['NM_172653', '-', 'chr1', 46798055, 46798056],
'Obfc2a' : ['NM_028696', '-', 'chr1', 51422944, 51422945],
'Myo1b' : ['NM_001161817', 'NM_010863', 'chr1', 51860519, 51860520],
})
data.get(['Slc40a1', 'Myo1b', 'Col5a2', 'Obfc2a'])
# Output:
Slc40a1 Myo1b Col5a2 Obfc2a
0 NM_016917 NM_001161817 NM_007737 NM_028696
1 - NM_010863 - -
2 chr1 chr1 chr1 chr1
3 45870140 51860519 45447828 51422944
4 45870141 51860520 45447829 51422945