কিভাবে এলোমেলোভাবে একটি ফাইলের একটি উপসেট নমুনা


38

ফাইলের সাবসেটের নমুনা ব্যবহারের জন্য লিনাক্সের কোন কমান্ড ব্যবহার করতে পারে? উদাহরণস্বরূপ, একটি ফাইলের মধ্যে এক মিলিয়ন লাইন রয়েছে এবং আমরা এলোমেলোভাবে সেই ফাইল থেকে কেবলমাত্র এক হাজার লাইনের নমুনা রাখতে চাই।

এলোমেলোভাবে আমি বোঝাতে চাইছি যে প্রতিটি লাইনই বেছে নেওয়ার একই সম্ভাবনা পায় এবং নির্বাচিত লাইনগুলির কোনওটিই পুনরাবৃত্তি করে না।

headএবং tailএলোমেলোভাবে ফাইলের একটি উপসেট বেছে নিতে পারে। আমি জানি আমি এটি করতে সর্বদা পাইথন স্ক্রিপ্ট লিখতে পারি তবে এই ব্যবহারের জন্য একটি আদেশ আছে কি না তা অবাক করেই ভাবছি।


এলোমেলোভাবে ক্রমে রেখাগুলি, বা সেই ফাইলের একটানা 1000 লাইনের একটি এলোমেলো ব্লক?
frostschutz

প্রতিটি লাইনই বেছে নেওয়ার একই সম্ভাবনা পায়। ধারাবাহিক হওয়ার দরকার নেই যদিও একটি ক্ষুদ্র সম্ভাবনা রয়েছে যে একটানা একটানা লাইনের লাইন বেছে নেওয়া হবে। আমি আমার প্রশ্নটি এই সম্পর্কে পরিষ্কার করার জন্য আপডেট করেছি। ধন্যবাদ।
উঠেছে

আমার github.com/barrycarter/bcapps/tree/master/bc-fastrand.pl এটি প্রায় ফাইলে একটি এলোমেলো অবস্থান অনুসন্ধান করে এবং নিকটস্থ নতুন লাইনগুলি সন্ধান করে এটি করে।
ব্যারিকার্টার

উত্তর:


65

shufকমান্ড (coreutils অংশ) এটা করতে পারেন:

shuf -n 1000 file

এবং কমপক্ষে এখন অ-প্রাচীন সংস্করণগুলির জন্য ( ২০১৩ সালের একটি প্রতিশ্রুতিতে যুক্ত ), যা উপযুক্ত হলে জলাধার নমুনা ব্যবহার করবে, যার অর্থ এটির স্মৃতিশক্তি শেষ না হওয়া উচিত এবং একটি দ্রুত অ্যালগরিদম ব্যবহার করা হয়।


ডকুমেন্টেশন অনুসারে, এর ইনপুট হিসাবে একটি বাছাই করা ফাইলের প্রয়োজন: gnu.org/software/coreutils/manual/…
এমকেসি

@ কিতান, সেভাবে মনে হচ্ছে না
ফ্রস্টশুটজ

2
@ কিতান এটি ম্যানুয়ালটির ভুল বিভাগে রয়েছে, আমি বিশ্বাস করি। নোট করুন যে ম্যানুয়ালটিতে উদাহরণগুলিও সাজানো হয় না। নোটটিও sortএকই বিভাগে রয়েছে এবং এটি পরিষ্কারভাবে সাজানো ইনপুটের প্রয়োজন হয় না।
ডারোবার্ট

2
shufসংস্করণে কোর্টিলের সাথে পরিচয় করিয়ে দেওয়া হয়েছিল 6.0 (2006-08-15)এবং এটি বিশ্বাস করুন বা না বিশ্বাস করুন, কিছু যুক্তিসঙ্গত-সাধারণ সিস্টেমগুলির (বিশেষত সেন্টোস .5.৫) সংস্করণটি নেই: - |
offby1

2
@ পেটেলহার্প shuf -nজলাধার নমুনা দেয়, কমপক্ষে যখন ইনপুটটি 8 কে এর চেয়ে বেশি হয়, যা তারা নির্ধারিত আকারটি বেঞ্চমার্ক আরও ভাল। উত্স কোডটি দেখুন (যেমন, github.com/coreutils/coreutils/blob/master/src/shuf.c#L46 )। এই দেরী উত্তরের জন্য দুঃখিত। দৃশ্যত এটি 6 বছর আগের হিসাবে নতুন।
ডারোবার্ট

16

আপনার যদি খুব বড় ফাইল থাকে (যা কোনও নমুনা নেওয়ার একটি সাধারণ কারণ) আপনি তা দেখতে পাবেন:

  1. shuf স্মৃতি ক্লান্ত করে
  2. ব্যবহার $RANDOMসঠিকভাবে কাজ করবে না যদি ফাইলটি 32767 লাইন অতিক্রম করে

আপনার যদি "ঠিক" এন নমুনাযুক্ত রেখাগুলির প্রয়োজন না হয় আপনি এই জাতীয় অনুপাতটি নমুনা করতে পারেন :

cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt

এটি ধ্রুব স্মৃতি , ফাইলের 1% নমুনা ব্যবহার করে (যদি আপনি ফাইলের রেখার সংখ্যা জানেন তবে আপনি এই ফ্যাক্টরটিকে সীমিত সংখ্যক লাইনের কাছাকাছি নমুনা তৈরি করতে পারেন) এবং কোনও আকারের ফাইলের সাথে কাজ করে তবে তা হবে না রেখার একটি নির্দিষ্ট সংখ্যা প্রদান করুন, কেবল একটি পরিসংখ্যান অনুপাত।

দ্রষ্টব্য: কোডটি এখানে থেকে এসেছে: https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with-unix


কোনও ব্যবহারকারী যদি খালি নয় এমন রেখাগুলির প্রায় 1% চান তবে এটি খুব ভাল উত্তর। তবে ব্যবহারকারী যদি লাইনগুলির সঠিক সংখ্যা চান (যেমন, 1000000-লাইনের ফাইলের মধ্যে 1000), এটি ব্যর্থ হয়। আপনি যে উত্তরটি পেয়েছেন সেহেতু এটি কেবল একটি পরিসংখ্যানমূলক অনুমান করে। এবং আপনি উত্তরটি কি যথেষ্ট বুঝতে পেরেছেন যে এটি ফাঁকা রেখা উপেক্ষা করছে? অনুশীলনে এটি একটি ভাল ধারণা হতে পারে তবে সাধারণভাবে নথিভুক্ত বৈশিষ্ট্যগুলি কোনও ভাল ধারণা নয়।
জি-ম্যান

1
পিএস   সরলবাদী পদ্ধতিগুলি $RANDOM32767 লাইনের চেয়ে বড় ফাইলগুলির জন্য সঠিকভাবে কাজ করবে না। "ব্যবহারটি $RANDOMপুরো ফাইলটিতে পৌঁছায় না " বিবৃতিটি কিছুটা বিস্তৃত।
জি-ম্যান

@ জি-ম্যান প্রশ্নটি উদাহরণ হিসাবে দশ মিলিয়ন থেকে 10 কে লাইন পাওয়ার বিষয়ে কথা বলে মনে হচ্ছে। আশেপাশের কোনও উত্তরই আমার পক্ষে কার্যকর হয়নি (ফাইলগুলির আকার এবং হার্ডওয়্যার সীমাবদ্ধতার কারণে) এবং আমি এটি যুক্তিসঙ্গত আপস হিসাবে প্রস্তাব করি। এটি আপনাকে এক মিলিয়ন এর মধ্যে 10 কে লাইন পাবে না তবে বেশিরভাগ ব্যবহারিক উদ্দেশ্যে এটি যথেষ্ট কাছাকাছি থাকতে পারে। আপনার পরামর্শ অনুসরণ করে আমি এটি আরও কিছুটা স্পষ্ট করেছি। ধন্যবাদ।
Txangel

এটি সর্বোত্তম উত্তর, মূল ফাইলের কালানুক্রমিক ক্রমকে সম্মান করার সময় লাইনগুলি এলোমেলোভাবে বাছাই করা হয়, যদি এটি কোনও প্রয়োজন হয়। অতিরিক্ত awkহ'ল সম্পদ বান্ধবshuf
পলিমারেজ

আপনার যদি একটি সঠিক নম্বর প্রয়োজন হয়, আপনি সর্বদা ... আপনার প্রয়োজনের চেয়ে আরও বড়% দিয়ে চালাতে পারেন। ফলাফল গণনা করুন। গণনা মোডের পার্থক্যের সাথে মিল রেখে লাইনগুলি সরান।
ব্রুনো ব্রোনোস্কি

6

@ টেক্সানগেলের সম্ভাব্য সমাধানের মতো তবে দ্রুত 100x দ্রুত এগিয়ে আসছে।

perl -ne 'print if (rand() < .01)' huge_file.csv > sample.csv

আপনার যদি উচ্চ পারফরম্যান্স, সঠিক নমুনা আকারের প্রয়োজন হয় এবং ফাইলটির শেষে নমুনা ফাঁক দিয়ে বেঁচে থাকতে খুশি হন তবে আপনি নিম্নলিখিতগুলির মতো কিছু করতে পারেন (1 মি লাইনের ফাইল থেকে 1000 লাইনের নমুনা):

perl -ne 'print if (rand() < .0012)' huge_file.csv | head -1000 > sample.csv

.. বা প্রকৃতপক্ষে পরিবর্তে একটি দ্বিতীয় নমুনা পদ্ধতি চেইন head


5

যদি shuf -nবড় ফাইল উপর কৌতুক মেমরি রান আউট এবং আপনি এখনও একটি নির্দিষ্ট আকার নমুনা প্রয়োজন এবং একটি বহিস্থিত ইউটিলিটি তারপর চেষ্টা ইনস্টল করা যাবে নমুনা :

$ sample -N 1000 < FILE_WITH_MILLIONS_OF_LINES 

সতর্কতাটি হ'ল নমুনাটি (উদাহরণে 1000 টি লাইন) অবশ্যই মেমরির সাথে মাপসই করা উচিত।

দাবি অস্বীকার: আমি প্রস্তাবিত সফ্টওয়্যারটির লেখক।


1
যারা এটি ইনস্টল করে এবং তাদের পথে /usr/local/binআগে /usr/bin/রয়েছে তাদের পক্ষে সাবধান থাকুন যে ম্যাকোস একটি বিল্ট-ইন কল-স্ট্যাক স্যাম্পলার নামে ডেকে নিয়ে আসে sample, যা সম্পূর্ণ আলাদাভাবে কিছু করে /usr/bin/
ডেনিস ডি বার্নার্ডি

2

আপনি যা চান তা করতে পারে এমন কোনও কমান্ড সম্পর্কে সচেতন নয় তবে এখানে একটি লুপ আমি একসাথে রেখেছি যা কাজটি করতে পারে:

for i in `seq 1000`; do sed -n `echo $RANDOM % 1000000 | bc`p alargefile.txt; done > sample.txt

sed1000 পাসের প্রত্যেকটিতে একটি এলোমেলো লাইন তুলে নেবে। সম্ভবত আরও কার্যকর সমাধান আছে।


এই পদ্ধতিতে একাধিকবার একই লাইন পাওয়া সম্ভব?
উঠেছে

1
হ্যাঁ, একই লাইন নম্বরটি একাধিকবার পাওয়া বেশ সম্ভব। অতিরিক্তভাবে, $RANDOM0 এবং 32767 এর মধ্যে পরিসীমা রয়েছে So সুতরাং, আপনি ভালভাবে স্প্রেড লাইন নম্বর পাবেন না।
এম কে সি

কাজ করে না - একবারে এলোমেলোভাবে বলা হয়
বোহদান

2

আপনি একটি ফাইলের অনুসরণ কোডটি সংরক্ষণ করতে পারেন (উদাহরণস্বরূপ randextract.sh) এবং এরূপে কার্যকর করতে পারেন:

randextract.sh file.txt

---- ফাইল শুরু করুন ----

#!/bin/sh -xv

#configuration MAX_LINES is the number of lines to extract
MAX_LINES=10

#number of lines in the file (is a limit)
NUM_LINES=`wc -l $1 | cut -d' ' -f1`

#generate a random number
#in bash the variable $RANDOM returns diferent values on each call
if [ "$RANDOM." != "$RANDOM." ]
then
    #bigger number (0 to 3276732767)
    RAND=$RANDOM$RANDOM
else
    RAND=`date +'%s'`
fi 

#The start line
START_LINE=`expr $RAND % '(' $NUM_LINES - $MAX_LINES ')'`

tail -n +$START_LINE $1 | head -n $MAX_LINES

---- ফাইল শেষ করুন ----


3
আপনি এখানে র‌্যান্ডের সাথে কী করার চেষ্টা করছেন তা আমি নিশ্চিত নই, তবে $RANDOM$RANDOMপুরো পরিসরে "0 থেকে 3276732767" এ এলোমেলো সংখ্যা তৈরি করে না (উদাহরণস্বরূপ, এটি 1000100000 কিন্তু 1000099999 নয় উত্পন্ন করবে)।
গিলস 'খারাপ হয়ে যাওয়া বন্ধ করুন'

ওপিতে বলা হয়েছে, “প্রতিটি লাইনই বেছে নেওয়ার একই সম্ভাবনা পায়। … এখানে একটি ক্ষুদ্র সম্ভাবনা রয়েছে যে একটানা লাইনগুলি একসাথে বেছে নেওয়া হবে। "আমি এই উত্তরটিও ক্রিপ্টিক বলে মনে করি, তবে দেখে মনে হচ্ছে এটি একটি এলোমেলো শুরুর বিন্দু থেকে পরপর 10 লাইনের ব্লকটি বের করছে। ওপি যা চাইছে তা নয়।
জি-ম্যান 21

2

আপনি যদি ফাইলটিতে রেখার সংখ্যা জানেন (যেমন আপনার ক্ষেত্রে 1e6) তবে আপনি এটি করতে পারেন:

awk -v n=1e6 -v p=1000 '
  BEGIN {srand()}
  rand() * n-- < p {p--; print}' < file

যদি না হয়, আপনি সবসময় করতে পারেন

awk -v n="$(wc -l < file)" -v p=1000 '
  BEGIN {srand()}
  rand() * n-- < p {p--; print}' < file

এটি ফাইলটিতে দুটি পাস করবে, তবে এখনও পুরো ফাইলটিকে মেমরির মধ্যে সঞ্চয় করতে এড়াবে।

গনুহ উপর আরেকটি সুবিধা shufএটি ফাইলে লাইনের অর্ডার সংরক্ষিত কিতাব।

নোট করুন এটি অনুমান করা n হয় যে ফাইলের লাইন সংখ্যা। আপনি মুদ্রণ করতে চান pআউট প্রথম n ফাইলের লাইন (যা সম্ভাব্য আরো লাইন আছে), আপনি বন্ধ করতে হতে পারে চাই awkn মত লাইন:

awk -v n=1e6 -v p=1000 '
  BEGIN {srand()}
  rand() * n-- < p {p--; print}
  !n {exit}' < file

2

আমি যখন শিরোনাম সারিটি সংরক্ষণ করতে চাই এবং যখন নমুনাটি ফাইলের একটি আনুমানিক শতাংশ হতে পারে তখন আমি এর জন্য কুট্টাল ব্যবহার করতে চাই। খুব বড় ফাইলের জন্য কাজ করে:

awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01 || FNR==1) print > "data-sample.txt"}' data.txt

1

বা এই মত:

LINES=$(wc -l < file)  
RANDLINE=$[ $RANDOM % $LINES ]  
tail -n $RANDLINE  < file|head -1  

বাশ ম্যান পৃষ্ঠা থেকে:

        র্যান্ডোম প্রতিবার এই পরামিতিটি উল্লেখ করা হয়, এলোমেলো পূর্ণসংখ্যা
              0 থেকে 32767 এর মধ্যে উত্পন্ন হয়। এলোমেলো ক্রম
              RAN‐ এ একটি মান নির্ধারণের মাধ্যমে সংখ্যাগুলি শুরু করা যেতে পারে
              করে DOM। যদি র‌্যান্ডমটি সেট না করা থাকে তবে এটি তার বিশেষ যথাযথ হারায় ‐
              সম্পর্কগুলি, যদিও এটি পরে পুনরায় সেট করা হয়।

ফাইলটিতে 32767 টিরও কম লাইন থাকলে এটি খারাপভাবে ব্যর্থ হয়।
অফবি 1

এটি ফাইল থেকে এক লাইন আউটপুট দেবে । (আমার ধারণা আপনার ধারণাটি কোনও লুপে উপরের কমান্ডগুলি কার্যকর করা যায়?) যদি ফাইলটিতে 32767 টির বেশি লাইন থাকে তবে এই কমান্ডগুলি কেবল প্রথম 32767 লাইন থেকে বেছে নেবে। সম্ভাব্য অদক্ষতা বাদে, ফাইলটিতে 32767 টিরও কম লাইন থাকলে আমি এই উত্তর নিয়ে কোনও বড় সমস্যা দেখতে পাচ্ছি না।
জি-ম্যান 21

1

আপনি ফাইল আকার যদি বড় না হয়, আপনি এলোমেলো বাছাই করতে পারেন। এটি শফের চেয়ে কিছুটা বেশি সময় নেয় তবে এটি পুরো ডেটা এলোমেলো করে। সুতরাং, আপনি যেমন অনুরোধ করেছিলেন তেমন সহজেই হেডটি ব্যবহার করতে নিম্নলিখিতগুলি করতে পারেন:

sort -R input | head -1000 > output

এটি এলোমেলোভাবে ফাইলটি সাজান এবং আপনাকে প্রথম 1000 লাইন দেবে।


0

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.