我有一个包含许多行和列的数据文件。我想随机删除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
答案 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}
:仅当计数器在数组中(用随机值填充)时,才会打印过滤行。