1

我正在使用可视化工具来查看原子探针数据。

我的输出文件包含 4 列。每行包含原子的 x、y 和 z 坐标以及确定它是哪个原子的强度值。系统中的每个元素都有一个输出文件。

我有代码计算每个输出文件中的行数并将其除以总数以计算系统的组成。例如,如果每个输出文件中所有行数的总和为 100,而我的铁原子输出文件包含 85 行,那么系统的 85% 由铁原子组成。

现在,我想减少铁原子的数量,以便更容易看到其他原子。如何从输出文件中随机删除 90% 的行?我想做这样的条件:

if ($atom>80) {      #such as iron being 85
    #randomly remove lines, perhaps with rand()
}
4

2 回答 2

4

rand函数在区间 [0, 1) 中产生一个实数值。如果我们想要一个 90% 的时间返回 true 的条件,我们可以写rand() < 0.9. 因为你只想保留 10% 的铁原子:

my $percentage = shift @ARGV;
while (<>) {
  print unless this_record_is_iron() && rand() < $percentage;
}

然后:

$ perl reduce_iron.pl 0.9 input-data >reduced-data

如果我们想准确删除 90%,那么我会读入整个文件,创建一个指向铁记录的索引数组,打乱索引列表,然后删除除最后 10% 之外的所有内容:

use List::Util qw/shuffle/;
my $percentage = shift @ARGV;
my(@lines, @iron_idx);
while (<>) {
  push @lines, $_;
  push @iron_idx, $#lines if this_record_is_iron();
}
@iron_idx = (shuffle @iron_idx)[0 .. @iron_idx * $percentage - 1]; # keep indices to delete
$_ = "" for @lines[@iron_idx];
print @lines;
于 2013-07-23T17:23:00.620 回答
0

使用水库采样的细化实现:

#! /usr/bin/env perl

use strict;
use warnings;

use Fcntl qw/ SEEK_SET /;

die "Usage: $0 fraction file\n" .
    "  where 1 <= fraction <= 99\n"
  unless @ARGV == 2;

my($fraction,$path) = @ARGV;
die "$0: invalid fraction: $fraction"
  unless $fraction =~ /^[0-9]+$/ && $fraction >= 1 && $fraction <= 99;

open my $fh, "<", $path or die "$0: open $path: $!";
my $lines;
++$lines while defined($_ = <$fh>);

# modified Algorithm R from Knuth's TAoCP Volume 2, pg. 144
my $rsize = my $samples = int (($lines / 100) * $fraction);
my @delete = (1 .. $samples);
foreach my $t ($samples+1 .. $lines) {
  my $m = int(rand $t) + 1;
  $delete[$m] = ++$rsize if $m <= $samples;
}

seek $fh, 0, SEEK_SET or die "$0: seek: $!";
my %delete = map +($_ => 1), @delete;
$. = 1;
while (<$fh>) {
  print unless delete $delete{$.};
}
于 2013-07-23T22:32:23.023 回答