2013-07-23 5 views
1

Я использую визуализатор для просмотра данных зондового зонда.Как случайно удалить определенную часть строк файла?

Мои выходные файлы содержат 4 столбца. Каждая строка содержит координаты x, y и z атома плюс значение интенсивности, которое определяет, какой именно атом. Каждый элемент в системе имеет выходной файл.

У меня есть код, который подсчитывает количество строк в каждом выходном файле и делит его на общую сумму, чтобы рассчитать состав системы. Например, если сумма всего количества строк в каждом выходном файле равна 100, а мой выходной файл с атомом железа содержит 85 строк, 85% системы состоит из атомов железа.

Теперь я хочу уменьшить количество атомов железа, так что легче видеть другие атомы. Как я могу случайно удалить 90% строк из выходного файла? Я хочу сделать что-то вроде этого: условное

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

ответ

4

rand функция производит действительное значение в интервале [0, 1). Если мы хотим получить условие, которое возвращает истинное 90% времени, мы можем написать 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; 
+0

Возможно ли это, чтобы не удалить ровно 10% линий? Например, если у нас есть 100 строк, можем ли мы получить 89 или 91? – chilemagic

+0

@Matt Мое первое решение - * случайное *. В среднем мы удалим количество строк '$ percent'. Я добавил другое более точное решение; он удалит 'floor (ironAtoms · percent)' records. Поскольку это требует, чтобы мы знали количество атомов железа, мы должны прочитать во всем файле, который неэффективен для больших наборов данных. – amon

+0

У меня возникли проблемы с реализацией этого кода. Проблема в том, что я открываю выходной файл, записываю в 4 столбца данных и закрываю его для нескольких ионов (т. Е. Если имеется несколько атомов Fe с разными зарядами, у всех у них есть собственный файл). Затем я использую кошку для объединения всех ионов одного и того же элемента. Теперь, если новый файл элемента составляет достаточно большую часть системы (например, 80%), я хочу случайным образом удалить 90% этого файла. –

0

При реализации прореживания, который использует reservoir sampling:

#! /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{$.}; 
} 
Смежные вопросы