我有如下一篇文本:(单词,单词域)
car transport
car machine
bank economy
bank politics
bank parks
God religion
...
单词有很多,有些单词有不同的域,有些单词只有一个域。我有另一个文件,一个巨大的矩阵(每行 300 维),由单词和每个单词的向量组成,如下所示:
bank 0.9 1.5 3.2 -0.2 0.1 ...
God 1.0 2.1 -0.5 0.7 ...
rose 0.2 -1.8 ...
... ...
我想读取第一个文件中每个单词出现的次数,并根据该值选择第二个文件的每个向量中最高的“n”数字,知道它属于哪个字段。像这样的东西:
car 2
bank 3
God 1
并将这些数字传递给
bank 4 3.2
bank 3 1.5
bank 2 0.9
God 3 2.1
我想到的第一部分
gawk 'NR==FNR {a[$1]++;next;} dont know what here?' list matrix
我知道它有点复杂,但我们将不胜感激。也许另一种方法更容易?
答案1
awk '
NR==FNR{ #operate matrix file first
A[$1] = 1 #array of words
for(i=2;i<=NF;i++)
B[$1 OFS i] = $i #array with indexes [word field_num]
next
}
$1 in A{ #if word in array A
max = $1 OFS 2
for(i in B)
if(i ~ "^" $1 && B[max] < B[i])
max = i #find maximum in B-array
print max, B[max] #output word + field_num + value
delete B[max] #exclude value from next search
}
}
' matrix list
如果 awk 版本允许伪多维数组,则可以简化脚本
awk '
NR==FNR{
for(i=2;i<=NF;i++)
A[$1][i] = $i
next
}
$1 in A{
max = 2
for(i in A[$1])
if(A[$1][max] < A[$1][i])
max = i
print $1, max, A[$1][max]
delete A[$1][max]
}
}
' matrix list
答案2
这确实相当复杂。我建议创建一个awk
脚本,除非有人想出一个奇迹般的台词。
在你的awk
文件中:
NR==FNR {
a[$1]++
next
} #Your probably know what that does since it's your starting point
# If first field is a key in array a
$1 in a {
# Assign the number of occurences of this word in variable n
n=a[$1]
# Initialize this value to + INFINITY
k=-log(0)
# Loop on the number of occurences of the word
for (i=0; i<n; i++) {
# Initialize max value and its index at the first value of the vector
m=$2
i_m=2
# Loop on the number of fields in the matrix for that word
for (j=3; j<NF+1; j++) {
# Look for the largest value that stays below previous max (if none then k is INFINITY)
if ($j > m && $j < k) { m=$j; i_m=j }
}
# Print the word, the index of its max and its value
printf $1" "i_m" "m"\n"
# Store the max to be able to scan for the next biggest number at next iteration
k=m
}
}
运行它:
$ awk -f myScript.awk list matrix
我的脚本似乎工作正常,除了一种情况:如果某个单词在 中出现的次数等于或大list
于其向量中的值matrix
。这似乎不是这里的问题,因为你的向量非常大。另外, k
at的初始化-log(0)
以获取它的inf
值有点奇怪,但我不知道如何inf
直接将其设置为(=inf
显然不起作用)。你也许可以让它处理更多的情况(例如,如果你的向量中有几次相同的值......),但我会把它留给你,因为你现在有了一个起点!
答案3
(let ((h (hash :equal-based)))
(awk (:inputs "word-dom-pairs")
(t (inc [h [f 0] 0])))
(awk (:inputs "word-vectors")
(t (whenlet ((count [h [f 0]]))
(fconv - : r)
(let* ((n-fn-pairs (zip (rest f) (range 2)))
(n-fn-sorted [sort n-fn-pairs > first]))
(each ((p [n-fn-sorted 0..count]))
(prn [f 0] (second p) (first p))))))))
跑步:
$ txr munge.tl
bank 4 3.2
bank 3 1.5
bank 2 0.9
God 3 2.1
数据:
$ cat word-dom-pairs
car transport
car machine
bank economy
bank politics
bank parks
God religion
$ cat word-vectors
bank 0.9 1.5 3.2 -0.2 0.1
God 1.0 2.1 -0.5 0.7
rose 0.2 -1.8
以下是将程序合并为单个awk
表达式的版本:
(awk (:inputs "word-dom-pairs" "word-vectors")
(:let (h (hash :equal-based)))
((= arg 1) (inc [h [f 0] 0]))
((= arg 2) (whenlet ((count [h [f 0]]))
(fconv - : r)
(let* ((n-fn-pairs (zip (rest f) (range 2)))
(n-fn-sorted [sort n-fn-pairs > first]))
(each ((p [n-fn-sorted 0..count]))
(prn [f 0] (second p) (first p)))))))
:inputs
之前单独的两个awk
-s 合并为一个。我们t
根据变量给出的输入进行处理,用选择器替换无条件为真的模式arg
。绑定哈希表变量的内容let
被折叠到 awk 宏子句中:let
。
如果我们删除该(:inputs ...)
子句,我们可以使用一对命令行参数提供文件:
$ txr munge.tl file1 file2
TXR Lisp 是一种类型安全的动态语言,其中变量必须在赋值或使用之前定义。不存在的变量和垃圾字符串不是数字零,也不是字符串看类似的数字不是那些数字。这就是为什么我们显式定义哈希表的存在,并使用fconv
显式将第二个及后续字段转换为实数(r
)。