এলোমেলোভাবে একটি ডেটা ফাইল থেকে নির্দিষ্ট সংখ্যক লাইন আঁকুন


13

আমার মতো একটি ডেটা তালিকা রয়েছে

12345
23456
67891
-20000
200
600
20
...

এই ডেটা সেট (যেমন ফাইলের লাইন) এর আকারটি ধরুন N। আমি mএই তথ্য ফাইল থেকে এলোমেলোভাবে লাইন আঁকতে চাই । অতএব, আউটপুট দুটি ফাইল হওয়া উচিত, একটি হ'ল ফাইলের mডেটা এই লাইনগুলি সহ , এবং N-mঅন্যটিতে ডেটা লাইন অন্তর্ভুক্ত ।

লিনাক্স কমান্ড ব্যবহার করে কি উপায় আছে?


1
আপনি লাইন ক্রম সম্পর্কে উদ্বিগ্ন? যেমন। আপনি কি উত্স ক্রম বজায় রাখতে চান, বা আপনি চান যে ক্রমটি এলোমেলো হয়ে ওঠার পাশাপাশি লাইনের পছন্দটি এলোমেলো হতে পারে?
পিটার.ও

উত্তর:


18

এটি সবচেয়ে কার্যকর উপায় নাও হতে পারে তবে এটি কাজ করে:

shuf <file> > tmp
head -n $m tmp > out1
tail -n +$(( m + 1 )) tmp > out2

সঙ্গে $mলাইনের সংখ্যা থাকে।


@ ব্যবহারকারীর জানা, এলোমেলোতার sort -Rযত্ন নেয়। আপনি যদি এর জন্য উত্তরটি কমে যান তা নিশ্চিত নন, তবে প্রথমে ম্যানপেজে এটি সন্ধান করুন।
রব ওয়াটারস

2
মনে রাখবেন যে sort -Rএর ইনপুটটি এলোমেলোভাবে ঠিক সাজান না: এটি অভিন্ন লাইনের গ্রুপ করে। তাই আপনি যদি ইনপুট যেমন foo, foo, bar, barও মি = 2, তারপর এক ফাইল উভয় উপস্থিত থাকবে foos এবং অন্যান্য উভয় উপস্থিত থাকবে barসে। জিএনইউ কোর্টিলগুলিতেও রয়েছে shuf, যা ইনপুট লাইনগুলিকে এলোমেলো করে দেয়। এছাড়াও, আপনার একটি অস্থায়ী ফাইলের প্রয়োজন নেই
গিলস 'তাই খারাপ হওয়া বন্ধ করুন'

কেন না shuf <file> |head -n $m?
ইমানুয়েল

@ ইমানুয়েল: কারণ আমাদের দুটি পৃথক ফাইলে মাথা এবং লেজ উভয়ই দরকার।
রব ওয়াটারস

5

এই বাশ / অ্যাজক স্ক্রিপ্টটি এলোমেলোভাবে লাইনগুলি চয়ন করে এবং উভয় আউটপুট ফাইলগুলিতে মূল ক্রম বজায় রাখে।

awk -v m=4 -v N=$(wc -l <file) -v out1=/tmp/out1 -v out2=/tmp/out2 \
 'BEGIN{ srand()
         do{ lnb = 1 + int(rand()*N)
             if ( !(lnb in R) ) {
                 R[lnb] = 1
                 ct++ }
         } while (ct<m)
  } { if (R[NR]==1) print > out1 
      else          print > out2       
  }' file
cat /tmp/out1
echo ========
cat /tmp/out2

আউটপুট, প্রশ্নে ডেটা ভিত্তিক।

12345
23456
200
600
========
67891
-20000
20

4

সবকিছুর মতো ইউনিক্স, সেখানে একটি ইউটিলিটি অফ দ্য টিএম

দিনের প্রোগ্রাম: split
splitএকটি ফাইলকে বিভিন্ন উপায়ে, -bবাইট, -lলাইন, -nআউটপুট ফাইলের সংখ্যা বিভক্ত করবে । আমরা -lবিকল্পটি ব্যবহার করব । যেহেতু আপনি এলোমেলো লাইন বেছে নিতে চান এবং কেবল প্রথমটি নয় m, আমরা sortপ্রথমে ফাইলটি এলোমেলোভাবে করব । আপনি যদি পড়তে চান তবে sortআমার উত্তরটি এখানে উল্লেখ করুন

এখন, আসল কোড। এটি বেশ সহজ, সত্য:

sort -R input_file | split -l $m output_prefix

এটি দুটি ফাইল তৈরি করবে, একটি mলাইনযুক্ত এবং একটি N-mলাইনযুক্ত, নামযুক্ত output_prefixaaএবং output_prefixab। আপনার যে mবৃহত ফাইল চান তা নিশ্চিত হয়ে নিন বা আপনি দৈর্ঘ্যের বেশ কয়েকটি ফাইল m(এবং এর সাথে একটি N % m) পাবেন।

আপনি যদি সঠিক আকারটি ব্যবহার করেন তা নিশ্চিত করতে চান তবে এটি করার জন্য এখানে একটি সামান্য কোড রয়েছে:

m=10 # size you want one file to be
N=$(wc -l input_file)
m=$(( m > N/2 ? m : N - m ))
sort -R input_file | split -l $m output_prefix

সম্পাদনা: এটা আমার নজরে এসেছে যে কিছু sortবাস্তবায়নের -Rপতাকা নেই। আপনার যদি থাকে perl, আপনি বিকল্প করতে পারেন perl -e 'use List::Util qw/shuffle/; print shuffle <>;'


1
দুর্ভাগ্যক্রমে, sort -Rকেবল সাজানোর কিছু সংস্করণে উপস্থিত হতে পারে (সম্ভবত gnu সংস্করণ)। অন্যান্য প্ল্যাটফর্মের জন্য আমি একটি সরঞ্জাম লিখেছিলাম 'র্যান্ডলাইন' যা স্ট্যান্ডিনকে এলোমেলো করে তোলা ছাড়া কিছুই করে না। যার প্রয়োজন হয় তার জন্য এটি beesbuzz.biz/codeরয়েছে । (আমি ফাইলের বিষয়বস্তুগুলিকে বেশ
বদলাতে চাই

1
মনে রাখবেন যে sort -Rএর ইনপুটটি এলোমেলোভাবে ঠিক সাজান না: এটি অভিন্ন লাইনের গ্রুপ করে। তাই আপনি যদি ইনপুট যেমন foo, foo, bar, barও মি = 2, তারপর এক ফাইল উভয় উপস্থিত থাকবে foos এবং অন্যান্য উভয় উপস্থিত থাকবে barসে। জিএনইউ কোর্টিলগুলিতেও রয়েছে shuf, যা ইনপুট লাইনগুলিকে এলোমেলো করে দেয়। এছাড়াও, আপনি এর পরিবর্তে headএবং এর tailপরিবর্তে আউটপুট ফাইলের নামগুলি চয়ন করতে পারেনsplit
গিলস 'অসন্তুষ্ট হওয়া বন্ধ করুন'

4

আপনি যদি লাইনগুলিকে পুনর্বিন্যাস করতে আপত্তি করেন না এবং আপনার জিএনইউ কোর্টিলস রয়েছে (যেমন shufসংস্করণ .0.০-এ প্রকাশিত হওয়ার পরে খুব প্রাচীন নয় ), shuf("বদলানো") এলোমেলোভাবে কোনও ফাইলের লাইনগুলিকে পুনর্বিন্যাস করে। সুতরাং আপনি ফাইলটি পরিবর্তন করতে পারবেন এবং প্রথম মিটার লাইনগুলি একটি ফাইলে এবং বাকী অন্যটিতে প্রেরণ করতে পারেন।

এই প্রেরণ করার কোনও আদর্শ উপায় নেই। আপনি কেবল চেইন করতে পারবেন না headএবং tailকারণ headএটি সামনে বাফার করবে। আপনি ব্যবহার করতে পারেন split, তবে আউটপুট ফাইলের নামের সাথে আপনি কোনও নমনীয়তা পাবেন না। আপনি awkঅবশ্যই ব্যবহার করতে পারেন :

<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'

আপনি ব্যবহার করতে পারেন sed, এটি অস্পষ্ট তবে বড় ফাইলগুলির জন্য সম্ভবত দ্রুত।

<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2

বা teeআপনার প্ল্যাটফর্মটি থাকলে ডেটা সদৃশ করতে ব্যবহার করতে পারেন /dev/fd; ঠিক আছে যদি মি ছোট হয়:

<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2

পোর্টেবলভাবে, আপনি প্রতিটি লাইন ঘুরে ফিরে প্রেরণ করতে বিশ্রী ব্যবহার করতে পারেন। মনে রাখবেন যে এ্যান্ড্কটি এর এলোমেলো নম্বর জেনারেটর শুরু করতে খুব ভাল নয়; এলোমেলোতা কেবল ক্রিপ্টোগ্রাফির জন্য অবশ্যই উপযুক্ত নয়, তবে সংখ্যার সিমুলেশনের জন্য খুব ভালও নয়। এক-দ্বিতীয় সময়কালের সাথে যে কোনও সিস্টেমে সমস্ত বীজ অনুরোধের জন্য বীজ একই হবে।

<input awk -v N=$(wc -l <input) -v m=3 '
    BEGIN {srand()}
    {
        if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
        --N;
    }'

আপনার যদি আরও ভাল এলোমেলো প্রয়োজন হয়, আপনি পার্লে একই জিনিসটি করতে পারেন, যা এর আরএনজি শালীনভাবে বীজ করে।

<input perl -e '
    open OUT1, ">", "output1" or die $!;
    open OUT2, ">", "output2" or die $!;
    my $N = `wc -l <input`;
    my $m = $ARGV[0];
    while (<STDIN>) {
        if (rand($N) < $m) { --$m; print OUT1 $_; } else { print OUT2 $_; }
        --$N;
    }
    close OUT1 or die $!;
    close OUT2 or die $!;
' 42

@Gilles: জন্য awkউদাহরণ: -v N=$(wc -l <file) -v m=4... এবং এটি শুধুমাত্র একটি ছাপে "এলোমেলো" লাইন যখন র্যান্ডম মান কম $m, বরং প্রিন্টিং বেশী $mএলোমেলো লাইন ... মনে হচ্ছে যে perlসঙ্গে একই জিনিস করছেন হতে পারে রান্ড , কিন্তু আমি ডন perlসংকলনের ত্রুটিটি পার করার জন্য যথেষ্ট ভাল জানেন না:
সংলগ্ন

@ পিটার.ও ধন্যবাদ, এটিই ব্রাউজারে টাইপ করা এবং অযত্নে সম্পাদনা করা থেকে আসে। আমি awk এবং পার্ল কোডটি স্থির করেছি।
গিলস 'তাই খারাপ হওয়া বন্ধ করুন'

সমস্ত 3 টি পদ্ধতি ভাল এবং দ্রুত কাজ করছে .. ধন্যবাদ (+1) ... আমি আস্তে আস্তে আমার মাথাটি পার্লের চারপাশে পেয়ে যাচ্ছি ... এবং এটি shufউদাহরণের মধ্যে একটি বিশেষ আকর্ষণীয় এবং দরকারী ফাইল বিভাজন ।
পিটার.ও

বাফারিংয়ের সমস্যা? । আমি কিছু অনুপস্থিত করছি? head catকম্বো দ্বিতীয় পরীক্ষা নিম্নলিখিত ডেটা হারানো ঘটায় 3-4 .... পরীক্ষা 1-2 { for i in {00001..10000} ;do echo $i; done; } | { head -n 5000 >out1; cat >out2; } .. পরীক্ষা 3-4 { for i in {00001..10000} ;do echo $i; done; } >input; cat input | { head -n 5000 >out3; cat >out4; } ... wc -lআউটপুটের জন্য ফলাফল পরীক্ষা 1-2 হয় 5000 5000 (ভাল), কিন্তু জন্য পরীক্ষা 3-4 হয় 5000 4539 (না ভালো) .. differnece ফাইল জড়িত মাপ উপর নির্ভর করে পরিবর্তিত হয় ... এখানে আমার একটি লিঙ্ক পরীক্ষা কোড
Peter.O

@ পিটার.ও আবার, ধন্যবাদ। আসলে, headসামনে পড়া; এটি কী আগে পড়ে এবং প্রিন্ট আউট করে না তা বাতিল করা হয়। আমি আমার উত্তরটি কম মার্জিত সাথে আপডেট করেছি তবে (আমি যুক্তিসঙ্গত নিশ্চিত) সঠিক সমাধান দিয়েছি।
গিলস 'অসন্তুষ্ট হওয়া বন্ধ করুন'

2

ধরে নেওয়া m = 7এবং N = 21:

cp ints ints.bak
for i in {1..7}
do
    rnd=$((RANDOM%(21-i)+1))
    # echo $rnd;  
    sed -n "${rnd}{p,q}" 10k.dat >> mlines 
    sed -i "${rnd}d" ints 
done

দ্রষ্টব্য: আপনি যদি 7পরিবর্তনকের মতো $1বা এর পরিবর্তে $mআপনার ব্যবহার seqকরতে হয়, {from..to}নোটেশন নয়, যা ভেরিয়েবল সম্প্রসারণ করে না।

এটি ফাইল থেকে লাইন মুছে ফেলার মাধ্যমে কাজ করে, যা আরও কম এবং সংক্ষিপ্ত হয়, সুতরাং লাইন নম্বরটি, যা সরানো যেতে পারে, আরও ছোট এবং ছোট হতে হবে।

এই, আর ফাইল, এবং অনেক লাইন জন্য ব্যবহৃত উচিত নয় যেহেতু প্রত্যেক সংখ্যার জন্য গড়ে, অর্ধেক ফাইল চাহিদা 1st জন্য পড়তে হবে, এবং 2nd জন্য সম্পূর্ণ ফাইল sed কোড।


লাইনগুলিও মুছে ফেলা হয়েছে এমন একটি ফাইল তার দরকার।
রব ওয়াটারস

আমি ভেবেছিলাম "ডেটাগুলির এই এম লাইনগুলি সহ" এর অর্থ হওয়া উচিত including themতবে মূল লাইনগুলিও - সুতরাং including, না consisting ofএবং ব্যবহার হচ্ছে না onlyতবে আমি অনুমান করি যে আপনার ব্যাখ্যার অর্থ ব্যবহারকারী 288609 বলতে কী বোঝায়। আমি সেই অনুযায়ী আমার স্ক্রিপ্ট সামঞ্জস্য করব।
ব্যবহারকারী অজানা

ভাল লাগছে। `` ``
রব ওয়াটারস

@ ব্যবহারকারী অজানা: +1আপনার ভুল জায়গায় রয়েছে। rnd=$((RANDOM%(N-i)+1))আপনার উদাহরণে এন = 21 যেখানে এটি হওয়া উচিত .. এটি sedযখন rndমূল্যায়ন করা হয় তখন এটি ক্র্যাশ হয়ে যায় 0। .. এছাড়াও, ফাইলটি পুনরায় লেখার সাথে এটি খুব ভাল স্কেল করে না। যেমন 123 সেকেন্ড একটি 10,000 লাইন ফাইল থেকে 5,000 র্যান্ডম লাইন বের করে আনতে বনাম 0.03 সেকেন্ড একটি অধিক প্রত্যক্ষ পদ্ধতি জন্য ...
Peter.O

@ পিটার.ও: আপনি ঠিক বলেছেন (সংশোধন করেছেন) এবং আপনি ঠিক বলেছেন।
ব্যবহারকারী অজানা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.