如何提取具有非零列值的行?
Posted
技术标签:
【中文标题】如何提取具有非零列值的行?【英文标题】:How to extract rows with non-zeros column values? 【发布时间】:2019-10-19 12:37:10 【问题描述】:给定一个这样的 tsv 文件:
doc_id/query_id 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
1000001 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1000002 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
第一行是标题角色,doc_id/query_id
作为第一列标题,[1,150]
中的 150 个整数。
值行由第一列中的 ID 和零或其他列组成。
目标是提取成对的 ID 和非零列的名称,例如鉴于所需输出上方的两行数据是:
1000001 4
1000001 9
1000002 7
1000002 8
数据中有800,000行,所以我会避免pandas
而使用sframe
,我试过了:
import turicreate as tc
from tqdm import tqdm
df = tc.SFrame('data.tsv')
with open('ground_truth.non-zeros.tsv', 'w') as fout:
for i in tqdm(range(len(df))):
for j in range(1,151):
if df[i][str(j)]:
print(df[i]['doc_id/query_id', j)
有没有更简单的方法来提取非零值和行 ID?
Pandas 解决方案或其他数据框解决方案也很受欢迎!如果知道的话,请务必说明限制,如果有的话 =)
【问题讨论】:
哦,nvm。我认为这是一个熊猫问题,因为它被标记为熊猫:p Pandas 解决方案也很受欢迎 =) 【参考方案1】:这是使用stack
和query
的熊猫方法:
(df.set_index('doc_id/query_id')
.stack()
.to_frame('tmp')
.query('tmp == 1')
.index
.values)
array([(1000001, '4'), (1000001, '9'), (1000002, '7'), (1000002, '8')],
dtype=object)
这是一种先优雅,后性能的方法。
您也可以从 numpy 开始,这是为了获得最佳性能。
arr = np.loadtxt(filename, skiprows=1, usecols=np.r_[1:151], dtype=int)
index = np.loadtxt(filename, skiprows=1, usecols=[0], dtype=int)
r, c = np.where(arr)
np.column_stack([index[r], c+1])
array([[1000001, 4],
[1000001, 9],
[1000002, 7],
[1000002, 8]])
【讨论】:
【参考方案2】:这是基于numpy
的一种方式,我认为应该稍微加快整个过程
t,v=np.where(df.iloc[:,1:]==1)
list(zip(df['doc_id/query_id'].iloc[t],df.columns[v+1]))
Out[135]: [(1000001, '4'), (1000001, '9'), (1000002, '7'), (1000002, '8')]
【讨论】:
【参考方案3】:一个非熊猫的答案,你可以遍历你的文件,并在必要时抓取列:
results = []
with open('yourfile.csv') as fh:
headers = next(fh).split()
for line in fh:
_id, *line = line.split()
non_zero = [_id: header for header, val in zip(headers[1:], line) if val!="0"]
results.extend(non_zero)
# Where you now have the option to throw it into whatever data structure you want
results
['1000001': '4', '1000001': '9', '1000002': '7', '1000002': '8']
这样您不会将整个文件加载到内存中,您只需要获取所需的内容,尽管您需要为list.extend
操作付费
【讨论】:
以上是关于如何提取具有非零列值的行?的主要内容,如果未能解决你的问题,请参考以下文章