-4

100万行を超えるテキストファイルがあります。個々の行はそれほど大きくありません(それぞれ約200〜270文字)。

入力の行数の60%をランダムに選択しようとしています。ここで、各行を出力で繰り返すことができます。上記の例では、出力には600,000行が含まれますが、そのうち500,000行だけが一意である可能性があります。また、まったく選択されていない行を別の出力ファイルに入れる必要があります。個々の行は、両方の出力ファイルに表示されないようにする必要があります。

入力ファイルの各行には、次のようなレコードがあります。

  • Record1
  • Record2
  • Record3
  • Record4
  • Record5
  • Record6
  • Record7

ファイルoutput1.txtで5つのランダムな行を選択しようとしている場合、各行を繰り返すことができます。以下が選択された行であり、output1.txtにあるとしましょう

  • Record3
  • Record5
  • Record2
  • Record2
  • Record5

残りのレコードはoutput2.txtに移動する必要があります。

  • Record1
  • Record4
  • Record6
  • Record7

レコードの順序は重要ではありません。

Javaを使用してこれを行うためのコードを記述できると思いますが、コマンドまたはスクリプトを使用してすばやく実行できるのではないかと思っていました。'shuf'を使用して行を選択しようとしましたが、選択した行が取得しようとしている2番目の出力に表示されないようにするにはどうすればよいですか。

Linuxマシンで作業しています。提案やコメントは大歓迎です。ありがとう。

4

6 に答える 6

2

これがPerlソリューションです。

私は最近これをたくさん書いているようですが、非常に大きなテキストファイルにインデックスを付けることは、ファイル全体をメモリに読み込まずにランダムアクセスを取得するための最良の方法です。

このプログラムは、tell演算子を使用してソースファイル内の現在のレコードのオフセットを確立し、演算子を使用seekして特定のレコードに戻り、vec選択されたレコードを追跡します。

do { ... } while EXPRフォームは、最初に条件をチェックする前にdo-blockを実行し、この目的のために特別に選択されていることに注意してください。

プログラムは、コマンドラインで指定されたデータについてファイルがスキャンされることを想定しています。出力ファイルはselected.txt、選択された60%とunselected.txt残りのファイル用です。

use strict;
use warnings;

my $file = shift or die "No input file specified";

open my $infh, '<', $file or die qq(Unable to open "$file" for input: $!);
my @index;
do { push @index, tell $infh } while <$infh>;

my $used = "\0" x (@index / 8 + 1);

my $outfh;

open $outfh, '>', 'selected.txt' or die $!;
my $n = 0;
while ($n++ / @index < 0.6) {
  my $rec = int rand scalar @index;
  seek $infh, $index[$rec], 0;
  print $outfh scalar <$infh>;
  vec($used, $rec, 1) = 1;
}

open $outfh, '>', 'unselected.txt' or die $!;
for my $rec (0 .. $#index) {
  next if vec($used, $rec, 1);
  seek $infh, $index[$rec], 0;
  print $outfh scalar <$infh>;
}

編集

私はモジュールを使用して非常に小さなコードを置き換えることを躊躇しますが、誰かがこのアプローチを好む場合に備えて、池上が推奨するようにTie::File使用するバージョンがあります。

use strict;
use warnings;

use Tie::File;

my $file = shift or die "No input file specified";

tie my @index, 'Tie::File', $file, mode => O_RDONLY
    or die qq(Unable to open "$file" for input: $!);

my $outfh;
my @used;

open $outfh, '>', 'selected.txt' or die $!;
my $n = 0;
while ($n++ / @index < 0.6) {
  my $rec = int rand scalar @index;
  print $outfh $index[$rec], "\n";
  $used[$rec]++;
}

open $outfh, '>', 'unselected.txt' or die $!;
for my $rec (0 .. $#index) {
  print $outfh $index[$rec], "\n" unless $used[$rec];
}
于 2012-04-21T22:24:46.120 に答える
1

これにより、N / 6行が選択されるまで、ファイルのN行のうち1行がランダムに選択されます。重複の割合は制御されていません。

メモリを節約するために、行自体ではなく、メモリ内の行のファイル位置を保持します。Tie::Fileは私たちのためにそれを行います。

#!/usr/bin/env perl
use strict;
use warnings;

use Tie::File  qw( );

my ($input_qfn, $picked_qfn, $unpicked_qfn) = @ARGV;

tie(my @lines, 'Tie::File', $input_qfn, autochomp => 0)
   or die;

my $num_lines = @lines;
my @unpicked_indexes = 0..$num_lines-1;
my @picked_indexes;
for (1..$num_lines*.6) {
   my $rnd_idx = int(rand($num_lines));
   $unpicked_indexes[$rnd_idx] = undef;
   push @picked_indexes, $rnd_idx;
}

open(my $picked_fh, '>', $picked_qfn)
   or die $!;
print($picked_fh $lines[$_]) for @picked_indexes;

open(my $unpicked_fh, '>', $unpicked_qfn)
   or die $!;
print($unpicked_fh $lines[$_]) for grep defined, @unpicked_indexes;
于 2012-04-21T22:17:56.357 に答える
0

例〜STDOUTで10%を2回、STDOUTでさらに50%を1回、残りをSTDERRで40%

awk 'BEGIN {srand()} !/^$/ { r = rand(); if (r <= .60) print $0; if (r <= 0.10) print $0; if (r > .60) print $0 > "/dev/stderr"; }'

注:STDOUTを1つのファイルにリダイレクトし> file1、STDERRを別のファイルにリダイレクトします2> file2...

于 2012-04-21T20:36:43.513 に答える
0

bash scriptこのコードを使用してそれを行うことができます:

出力に行を繰り返さずに:

#!/bin/bash

lines=$(wc -l inputfile.txt | awk '{print $1}')

echo $lines

# computation of percentage of random lines we
# want to pick e.g. 60%
let percentage=$((lines*60/100))

echo $percentage

# pick the random lines
random_lines=$(sort -R inputfile.txt | head -n $percentage)

# show the random lines
echo $random_lines

出力に行が繰り返される場合:

#!/bin/bash

lines=$(wc -l inputfile.txt | awk '{print $1}')

echo $lines

# computation of percentage of random lines we
# want to pick e.g. 60%
let percentage=$((lines*60/100))

echo $percentage

# pick the random lines
for ((i=1; i<$percentage; i++))
do
  echo $(sort -R inputfile.txt | head -n 1)
done
于 2012-04-21T20:38:29.570 に答える
0

探している数学的専門用語は次のとおりです。100万個の要素のセットがあり、「置換あり」のサンプル要素を選択したい。さらに、選択されなかった要素を知りたいと思います。

universe = range(10**6)  # or whatever your elements are
numElementsToChoose = int(0.6*len(universe))

chosen = [random.choice(universe) for _ in range(numElementsToChoose)]
unchosen = set(universe) - set(chosen)

デモ:

>>> len(chosen), len(unchosen)
(600000, 548815)

(このコードはuniverseセットである必要があるためエレガントではありませんが、Pythonはセットからランダムな要素を選択することをネイティブにサポートしていません。シーケンスのみをサポートしています...うーん。)

于 2012-04-21T21:04:24.280 に答える
0

がある場合はshuf、おそらくがありますcomm。これには、2つのソートされたファイルを比較し、1つのファイルで見つかった行を出力する-3オプションがあります。

于 2012-04-22T00:48:22.723 に答える