使用shell删除包含特定列中特定字符串的50%的行

时间:2014-09-30 06:04:03

标签: shell

我有一个包含许多行和列的数据文件。我想随机删除50%的包含数字' 2'在第二栏。我怎样才能在shell脚本中执行此操作?我的文件看起来像这样:

264 2 -1.2000000000000000e+00 7.0825130926872939e+00 9.5601084339752944e+00 7.2651799153974066e+00 
245 4 2.3999999999999999e+00 3.2314933672268427e+00 8.1060222635488888e+00 4.9300995049182887e+00
602 2 2.3999999999999999e+00 7.9943142143951045e+00 8.9555257846190486e+00 6.1149829552712900e+00 
323 3 -1.2000000000000000e+00 9.5688081384508621e+00 1.0611671606914694e+01 8.9952891594417164e+00 
45 3 -1.2000000000000000e+00 9.4185463105240714e+00 9.3227605688201560e+00 6.6654941991009027e+00  
103 2 2.3999999999999999e+00 1.0178713184773681e+01 1.0522860587449216e+01 7.5396990175229996e+00 
462 2 2.3999999999999999e+00 4.2166316392533885e+00 6.9152554630316221e+00 7.5523911902369765e+00 
239 3 -1.2000000000000000e+00 7.8204053112970211e+00 8.2536094294868985e+00 9.4685060963111152e+00 
598 3 -1.2000000000000000e+00 7.9895230606907504e+00 7.3376809962958367e+00 6.1930783591087541e+00 

2 个答案:

答案 0 :(得分:4)

假设您的数据位于名为input的文件中:

awk 'BEGIN{srand()} $2!=2 || int(2*rand()) {print}' input

说明:

  • BEGIN{srand()}

    这为随机数生成器选择随机种子。这是在awk开始循环遍历文件的每一行之前完成的。

  • $2!=2 || int(2*rand()) {print}

    awk中,这是一个带条件的陈述。语句为print,它将打印整个当前行,但仅在条件为真时才打印。该条件有两个部分,它们是或者在一起。如果第二列具有除2之外的任何值,则条件为真:$2!=2。或者,如果int(2*rand())评估为非零,并且随机发生的概率为50%,则为真。

    因此,第二列等于2的大约一半的行被随机删除。

完全一半

如果让$2==2行保持50%的几率,则一个人不会保持50%,就像翻转一枚公平的硬币而不能完全 > 50%的负责人。假设偶数个受影响的行,恰好50%:

,以下代码补偿了该保留
awk 'BEGIN{srand()}
     NR==FNR && $2==2 {a[j++]=rand()}
     NR==FNR {next}
     FNR==1 {n=asort(a,b); cutoff=b[n/2]}
     $2!=2 {print; next}
     a[i++]<=cutoff {print}' input input

工作原理:以上内容经过两次。在第一次通过时,它会为$2==2的每一行分配一个随机数。这些值存储在数组a中。在第二次通过开始时,对这些数字进行排序并分配截止值。打印随机数小于或等于截止值的任何$2==2行。

因为它使用asort函数,所以需要GNU awk

答案 1 :(得分:2)

为了保证删除约50%,我们需要(提前)知道有多少“行”存储了“2”值。

awk 'function get_random(total) {
        while(1){
           a = sprintf(int(total * rand()))
           if (!( a in b )){
              b[a]++
              if (++i>int(total/2))
                 break
              }
           }
        }
     BEGIN{srand();k=0}
     NR==FNR{if ($2==2){total++};next}
     !i{get_random(total)}
     $2!=2{print;next}
     (sprintf(++k) in b){print}' inputfile inputfile

get_random:将参数作为参数获取受影响的记录数,while循环将在关联数组中存储总数/ 2(随机非重复)值(b)(使用转换为字符串)

NR==FNR{if ($2==2){total++};next}:第二个字段等于2的出现次数。

!i{get_random(total)}:当计数器i为空时调用该函数,我们正在文件的第二次迭代。

$2!=2{print;next}:打印不受影响的行

(sprintf(++k) in b){print}:仅当计数器在数组中(用随机值填充)时,才会打印过滤行。