J'ai une liste de données, comme
12345
23456
67891
-20000
200
600
20
...
Supposons que la taille de cet ensemble de données (c'est-à-dire les lignes de fichier) est N
. Je veux tracer au hasard des m
lignes à partir de ce fichier de données. Par conséquent, la sortie doit être de deux fichiers, l'un est le fichier comprenant ces m
lignes de données et l'autre inclut des N-m
lignes de données.
Existe-t-il un moyen de le faire en utilisant une commande Linux?
linux
shell
text-processing
user288609
la source
la source
Réponses:
Ce n'est peut-être pas le moyen le plus efficace mais cela fonctionne:
Avec
$m
contenant le nombre de lignes.la source
sort -R
prend soin de l'aléatoire. Je ne sais pas si vous avez dévalorisé la réponse pour cela, mais recherchez d'abord dans la page de manuel.sort -R
ne trie pas exactement son entrée au hasard: elle regroupe des lignes identiques. Donc , si l'entrée est par exemplefoo
,foo
,bar
,bar
et m = 2, puis un fichier contiendra les deuxfoo
s et l'autre contiendra les deuxbar
s. GNU coreutils a égalementshuf
, qui randomise les lignes d'entrée. De plus, vous n'avez pas besoin d'un fichier temporaire .shuf <file> |head -n $m
?Ce script bash / awk choisit des lignes au hasard et conserve la séquence d'origine dans les deux fichiers de sortie.
Sortie, basée sur les données de la question.
la source
Comme pour tout ce qui concerne Unix, il existe un utilitaire pour That TM .
Programme du jour:
split
split
divisera un fichier de différentes manières,-b
octets,-l
lignes,-n
nombre de fichiers de sortie. Nous utiliserons l'-l
option. Puisque vous voulez choisir des lignes aléatoires et pas seulement la premièrem
, nous allons d'sort
abord classer le fichier au hasard. Si vous voulez en savoir plussort
, référez-vous à ma réponse ici .Maintenant, le code réel. C'est assez simple, vraiment:
Cela fera deux fichiers, un avec des
m
lignes et un avec desN-m
lignes, nomméoutput_prefixaa
etoutput_prefixab
. Assurez-vous quem
le fichier est plus gros que vous voulez ou vous obtiendrez plusieurs fichiers de longueurm
(et un avecN % m
).Si vous voulez vous assurer que vous utilisez la bonne taille, voici un petit code pour le faire:
Edit: Il est venu à mon attention que certaines
sort
implémentations n'ont pas d'-R
indicateur. Si c'est le casperl
, vous pouvez remplacerperl -e 'use List::Util qw/shuffle/; print shuffle <>;'
.la source
sort -R
semble que ce ne soit que dans certaines versions (probablement la version GNU). Pour d'autres plates-formes, j'ai écrit un outil appelé «randline» qui ne fait que randomiser stdin. C'est sur beesbuzz.biz/code pour tous ceux qui en ont besoin. (J'ai tendance à beaucoup mélanger le contenu des fichiers.)sort -R
ne trie pas exactement son entrée au hasard: elle regroupe des lignes identiques. Donc , si l'entrée est par exemplefoo
,foo
,bar
,bar
et m = 2, puis un fichier contiendra les deuxfoo
s et l'autre contiendra les deuxbar
s. GNU coreutils a égalementshuf
, qui randomise les lignes d'entrée. En outre, vous pouvez choisir les noms des fichiers de sortie en utilisanthead
ettail
au lieu desplit
.Si cela ne vous dérange pas de réorganiser les lignes et que vous avez des coreutils GNU (c'est-à-dire sur Linux non intégré ou Cygwin, pas trop ancien depuis
shuf
apparu dans la version 6.0),shuf
("shuffle") réorganise les lignes d'un fichier de manière aléatoire. Vous pouvez donc mélanger le fichier et répartir les m premières lignes dans un fichier et le reste dans un autre.Il n'y a pas de moyen idéal pour faire cette dépêche. Vous ne pouvez pas simplement enchaîner
head
ettail
parcehead
que tamponner à l'avance. Vous pouvez utilisersplit
, mais vous n'obtenez aucune flexibilité en ce qui concerne les noms des fichiers de sortie. Vous pouvezawk
bien sûr utiliser :Vous pouvez utiliser
sed
ce qui est obscur mais peut-être plus rapide pour les gros fichiers.Ou vous pouvez utiliser
tee
pour dupliquer les données, si votre plate-forme a/dev/fd
; c'est ok si m est petit:De manière portable, vous pouvez utiliser awk pour distribuer chaque ligne tour à tour. Notez que awk n'est pas très bon pour initialiser son générateur de nombres aléatoires; le caractère aléatoire n'est pas seulement définitivement inapproprié pour la cryptographie, mais même pas très bon pour les simulations numériques. La graine sera la même pour toutes les invocations awk sur n'importe quel système avec une période d'une seconde.
Si vous avez besoin d'un meilleur caractère aléatoire, vous pouvez faire la même chose en Perl, qui amorce décemment son RNG.
la source
awk
exemple:-v N=$(wc -l <file) -v m=4
... et il n'imprime une ligne "aléatoire" que lorsque la valeur aléatoire est inférieure à$m
, plutôt que d'imprimer$m
des lignes aléatoires ... Il semble queperl
cela puisse faire la même chose avec rand , mais je ne fais pas ne sais pasperl
assez bien pour surmonter une erreur de compilation: erreur de syntaxe à -e ligne 7, près de ") print"shuf
exemple.head
cat
combo provoque la perte de données dans le deuxième test suivant 3-4 .... TEST 1-2{ for i in {00001..10000} ;do echo $i; done; } | { head -n 5000 >out1; cat >out2; }
.. TEST 3-4{ for i in {00001..10000} ;do echo $i; done; } >input; cat input | { head -n 5000 >out3; cat >out4; }
... leswc -l
résultats pour les sorties de TEST 1-2 sont 5000 5000 (bon), mais pour TEST 3-4 sont 5000 4539 (pas bon) .. La différence varie en fonction de la taille des fichiers impliqués ... Voici un lien vers mon code de testhead
lit à l'avance; ce qu'il lit à l'avance et ne s'imprime pas est supprimé. J'ai mis à jour ma réponse avec des solutions moins élégantes mais (je suis raisonnablement sûr) correctes.En supposant
m = 7
etN = 21
:Remarque: Si vous remplacez
7
par une variable comme$1
ou$m
, vous devez utiliserseq
, pas la{from..to}
-notation, qui ne fait pas d'extension de variable.Cela fonctionne en supprimant ligne par ligne du fichier, qui devient de plus en plus court, de sorte que le numéro de ligne, qui peut être supprimé, doit devenir de plus en plus petit.
Cela ne devrait pas être utilisé pour des fichiers plus longs et de nombreuses lignes, car pour chaque numéro, en moyenne, le demi-fichier doit être lu pour le 1er, et le fichier entier pour le 2ème code sed .
la source
including them
mais les lignes d'origine aussi - doncincluding
, nonconsisting of
, et ne pas utiliseronly
, mais je suppose que votre interprétation est, ce que signifiait user288609. J'ajusterai mon script en conséquence.+1
le mauvais endroit. Il devrait êtrernd=$((RANDOM%(N-i)+1))
où N = 21 dans votre exemple. Il provoque actuellement unsed
plantage lorsqu'ilrnd
est évalué0
. .. De plus, il ne s'adapte pas très bien avec toute la réécriture de ce fichier. par exemple 123 secondes pour extraire 5 000 lignes aléatoires d'un fichier de 10 000 lignes contre 0,03 secondes pour une méthode plus directe ...