3

我有一个看起来像这样的大型数据集:

5 6 5 6 3 5
2 5 3 7 1 6
4 8 1 8 6 9
1 5 2 9 4 5

对于每一行,我想从第二个字段中减去第一个字段,从第四个字段中减去第三个字段,依此类推,加深字段数(总是偶数)。然后,我想报告所有对的差异超过某个限制(比如 2)的那些行。我还应该能够报告下一个最佳行,即其中一对比较未能达到限制但所有其他对都符合限制的行。

从上面的示例中,如果我将限制设置为 2,那么我的输出文件应该包含最佳行:

2 5 3 7 1 6    # because (5-2), (7-3), (6-1) are all > 2
4 8 1 8 6 9    # because (8-4), (8-1), (9-6) are all > 2 

下一个最佳行

1 5 2 9 4 5    # because except (5-4), both (5-1) and (9-2) are > 2

我目前的方法是读取每一行,将每个字段保存为变量,做减法。但我不知道如何进一步进行。

谢谢,

4

5 回答 5

3

这是一种 bash 方法:

#!/bin/bash

threshold=$1
shift
file="$@"

a=($(cat "$file"))
b=$(( ${#a[@]}/$(cat "$file" | wc -l) ))

for ((r=0; r<${#a[@]}/b; r++)); do
    br=$((b*r))
    for ((c=0; c<b; c+=2)); do

        if [[ $(( ${a[br + c+1]} - ${a[br + c]} )) < $threshold ]]; then
            break; fi

        if [[ $((c+2)) == $b ]]; then
            echo ${a[@]:$br:$b}; fi

    done
done

用法:

$ ./script.sh 2 yourFile.txt
2 5 3 7 1 6
4 8 1 8 6 9

然后可以轻松地重定向此输出:

$ ./script.sh 2 yourFile.txt > output.txt

注意:如果您在每行之间有那些空行,这将无法正常工作......但我相信以上内容会让您顺利进行。

于 2012-11-09T18:27:17.277 回答
3

将“best”行打印到文件“best”,并将“next best”行打印到文件“nextbest”

awk '
{
        fail_count=0
        for (i=1; i<NF; i+=2){
                if ( ($(i+1) - $i) <= threshold )
                        fail_count++
        }
        if (fail_count == 0)
                print $0 > "best"
        else if (fail_count == 1)
                print $0 > "nextbest"
}
' threshold=2 inputfile

很简单的东西。

  1. 一次循环遍历字段 2。
  2. 如果(下一个字段 - 当前字段)不超过threshold,则递增fail_count
  3. 如果该行为fail_count零,则表示它属于“最佳”行。

    否则,如果该行fail_count是 1,则它属于“次佳”行。

于 2012-11-10T09:08:07.647 回答
1

我可能不会在 bash 中这样做。就我个人而言,我会用 Python 来做,这对于那些快速而肮脏的小脚本来说通常是好的。

如果您将数据保存在文本文件中,您可以在此处阅读有关如何将该数据作为行列表导入 Python 的信息。然后你可以使用一个for循环来处理每一行:

threshold = 2
results = []
for line in content:
    numbers = [int(n) for n in line.split()] # Split it into a list of numbers
    pairs = zip(numbers[::2],numbers[1::2]) # Pair up the numbers two and two.
    result = [abs(y - x) for (x,y) in pairs] # Subtract the first number in each pair from the second.
    if sum(result) > threshold:
        results.append(numbers)
于 2012-11-09T17:30:43.617 回答
1

另一个 bash 版本:

首先 acheck function只返回结果代码:

function getLimit() {
    local pairs=0 count=0 limit=$1 wantdiff=$2
    shift 2
    while [ "$1" ] ;do
        [ $(( $2-$1 )) -ge $limit ] && : $((count++))
        : $((pairs++))
        shift 2
      done
    test $((pairs-count)) -eq $wantdiff
}

比现在:

while read line ;do getLimit 2 0 $line && echo $line;done <file
2 5 3 7 1 6
4 8 1 8 6 9

while read line ;do getLimit 2 1 $line && echo $line;done <file
1 5 2 9 4 5
于 2012-11-10T13:17:04.570 回答
0

如果你可以使用awk

$ cat del1
5 6 5 6 3 5
2 5 3 7 1 6
4 8 1 8 6 9
1 5 2 9 4 5
1 5 2 9 4 5 3 9

$ cat del1 | awk '{
> printf "%s _ ",$0; 
> for(i=1; i<=NF; i+=2){
>     printf "%d ",($(i+1)-$i)}; 
>     print NF 
> }' | awk '{
> upper=0; 
> for(i=1; i<=($NF/2); i++){ 
>     if($(NF-i)>threshold) upper++
> }; 
> printf "%d _ %s\n", upper, $0}' threshold=2 | sort -nr
3 _ 4 8 1 8 6 9 _ 4 7 3 6
3 _ 2 5 3 7 1 6 _ 3 4 5 6
3 _ 1 5 2 9 4 5 3 9 _ 4 7 1 6 8
2 _ 1 5 2 9 4 5 _ 4 7 1 6
0 _ 5 6 5 6 3 5 _ 1 1 2 6

您可以根据需要进一步处理结果。结果按“好​​”顺序排序。

于 2017-05-16T02:13:49.107 回答