معالجة النص من ملف غير مسطح (لاستخراج المعلومات كما لو كان ملفًا مسطحًا)

StackOverflow https://stackoverflow.com/questions/2264504

سؤال

لدي مجموعة بيانات طولية تم إنشاؤها بواسطة محاكاة حاسوبية يمكن تمثيلها بالجداول التالية ('var' هي متغيرات):

time subject var1 var2 var3
t1   subjectA  ...
t2   subjectB  ...

و

subject   name
subjectA  nameA
subjectB  nameB

ومع ذلك، يقوم الملف الذي تم إنشاؤه بكتابة ملف بيانات بتنسيق مشابه لما يلي:

time t1 
  description
subjectA nameA
  var1 var2 var3
subjectB nameB
  var1 var2 var3
time t2
  description
subjectA nameA
  var1 var2 var3
subjectB nameB
  var1 var2 var3
...(and so on)

لقد كنت أستخدم برنامجًا نصيًا (python) لمعالجة بيانات الإخراج هذه في ملف نصي مسطح حتى أتمكن من استيرادها إلى R أو python أو SQL أو awk/grep لاستخراج المعلومات - مثال على نوع المعلومات المطلوبة من يظهر أدناه استعلام واحد (في تدوين SQL، بعد تحويل البيانات إلى جدول):

SELECT var1, var2, var3 FROM datatable WHERE subject='subjectB'

أتساءل عما إذا كان هناك حل أكثر كفاءة حيث يمكن أن يصل حجم كل ملف من ملفات البيانات هذه إلى 100 ميجابايت تقريبًا (ولدي المئات منها) ويستغرق إنشاء الملف النصي الثابت وقتًا طويلاً ويستهلك مساحة إضافية على القرص الصلب مع معلومات زائدة عن الحاجة.من الناحية المثالية، أود أن أتفاعل مع مجموعة البيانات الأصلية مباشرة لاستخراج المعلومات التي أرغب فيها، دون إنشاء ملف نصي مسطح إضافي...هل هناك حل awk/Perl أبسط لمثل هذه المهام؟أنا ماهر جدًا في معالجة النصوص بلغة بايثون ولكن مهاراتي في awk بدائية وليس لدي أي معرفة عملية بلغة Perl؛أتساءل عما إذا كانت هذه الأدوات أو غيرها من الأدوات الخاصة بالمجال يمكن أن توفر حلاً أفضل.

شكرًا!

حاشية:واو، شكرا للجميع!أنا آسف لأنني لا أستطيع اختيار إجابات الجميع @شكرًا.يشبه برنامج Python النصي التعليمات البرمجية الخاصة بك بدون خطوة التصفية.لكن مؤسستك نظيفة.@ب:اعتقدت أنني كنت ماهرًا بالفعل في grep ولكن على ما يبدو لا!هذا مفيد جدا...لكنني أعتقد أن الالتقاط يصبح صعبًا عند خلط "الوقت" في المخرجات (والذي فشلت في تضمينه كسيناريو استخراج محتمل في مثالي!هذا سيئي).@ghostdog74:هذا رائع فقط...لكن تعديل السطر للحصول على "الموضوع أ" لم يكن أمرًا سهلاً ...(على الرغم من أنني سأقرأ المزيد عن awk في هذه الأثناء وآمل أن أقرأ لاحقًا).@ويسمات:ذكر حسنا.@ إس لوت:هذا أنيق ومرن للغاية - لم أطلب حل python(ic) ولكنه يتناسب بشكل واضح مع إطار التحليل والتصفية والإخراج الذي اقترحه PP، وهو مرن بما يكفي لاستيعاب عدد من الاستعلامات المختلفة لاستخراج مختلف أنواع المعلومات من هذا الملف الهرمي.

مرة أخرى، أنا ممتن للجميع - شكرًا جزيلاً.

هل كانت مفيدة؟

المحلول

هذا هو ما تدور حوله مولدات بايثون.

def read_as_flat( someFile ):
    line_iter= iter(someFile)
    time_header= None
    for line in line_iter:
        words = line.split()
        if words[0] == 'time':
            time_header = [ words[1:] ] # the "time" line
            description= line_iter.next()
            time_header.append( description )
        elif words[0] in subjectNameSet:
            data = line_iter.next()
            yield time_header + data

يمكنك استخدام هذا مثل مكرر Python القياسي

for time, description, var1, var2, var3 in read_as_flat( someFile ):
    etc.

نصائح أخرى

إذا كان كل ما تريده هو var1، var2، var3 عند مطابقة موضوع معين، فيمكنك تجربة الأمر التالي:


  grep -A 1 'subjectB'

ال -A 1 ترشد وسيطة سطر الأوامر grep إلى طباعة السطر المطابق وسطرًا واحدًا بعد السطر المطابق (وفي هذه الحالة تأتي المتغيرات على سطر بعد الموضوع).

قد ترغب في استخدام -E خيار لإجراء بحث grep عن تعبير عادي وتثبيت البحث عن الموضوع في بداية السطر (على سبيل المثال grep -A 1 -E '^subjectB').

أخيرًا، سيتكون الإخراج الآن من سطر الموضوع وسطر المتغير الذي تريده.قد ترغب في إخفاء سطر الموضوع:


  grep -A 1 'subjectB' |grep -v 'subjectB'

وقد ترغب في معالجة السطر المتغير:


  grep -A 1 'subjectB' |grep -v 'subjectB' |perl -pe 's/ /,/g'

سيكون الخيار الأفضل هو تعديل محاكاة الكمبيوتر لإنتاج مخرجات مستطيلة.على افتراض أنك لا تستطيع أن تفعل ذلك، إليك طريقة واحدة:

لكي تتمكن من استخدام البيانات في R وSQL وما إلى ذلك.تحتاج إلى تحويله من الهرمي إلى المستطيل بطريقة أو بأخرى.إذا كان لديك بالفعل محلل يمكنه تحويل الملف بأكمله إلى مجموعة بيانات مستطيلة، فأنت على وشك تحقيق ذلك.الخطوة التالية هي إضافة مرونة إضافية إلى المحلل اللغوي الخاص بك، حتى يتمكن من تصفية سجلات البيانات غير المرغوب فيها.بدلاً من وجود محول ملفات، سيكون لديك أداة مساعدة لاستخراج البيانات.

المثال أدناه موجود في لغة Perl، ولكن يمكنك فعل الشيء نفسه في لغة Python.الفكرة العامة هي الحفاظ على فصل نظيف بين (أ) التحليل، (ب) التصفية، و (ج) الإخراج.بهذه الطريقة، لديك بيئة مرنة، مما يجعل من السهل إضافة طرق تصفية أو إخراج مختلفة، اعتمادًا على احتياجاتك الفورية في معالجة البيانات.يمكنك أيضًا إعداد طرق التصفية لقبول المعلمات (إما من سطر الأوامر أو ملف التكوين) لمزيد من المرونة.

use strict;
use warnings;

read_file($ARGV[0], \&check_record);

sub read_file {
    my ($file_name, $check_record) = @_;
    open(my $file_handle, '<', $file_name) or die $!;
    # A data structure to hold an entire record.
    my $rec = {
        time => '',
        desc => '',
        subj => '',
        name => '',
        vars => [],
    };
    # A code reference to get the next line and do some cleanup.
    my $get_line = sub {
        my $line = <$file_handle>;
        return unless defined $line;
        chomp $line;
        $line =~ s/^\s+//;
        return $line;
    };
    # Start parsing the data file.
    while ( my $line = $get_line->() ){
        if ($line =~ /^time (\w+)/){
            $rec->{time} = $1;
            $rec->{desc} = $get_line->();
        }
        else {
            ($rec->{subj}, $rec->{name}) = $line =~ /(\w+) +(\w+)/;
            $rec->{vars} = [ split / +/, $get_line->() ];

            # OK, we have a complete record. Now invoke our filtering
            # code to decide whether to export record to rectangular format.
            $check_record->($rec);
        }
    }
}

sub check_record {
    my $rec = shift;
    # Just an illustration. You'll want to parameterize this, most likely.
    write_output($rec)
        if  $rec->{subj} eq 'subjectB'
        and $rec->{time} eq 't1'
    ;
}

sub write_output {
    my $rec = shift;
    print join("\t", 
        $rec->{time}, $rec->{subj}, $rec->{name},
        @{$rec->{vars}},
    ), "\n";
}

إذا كنت كسولًا ولديك ذاكرة وصول عشوائي كافية، فسأعمل على قرص ذاكرة الوصول العشوائي بدلاً من نظام الملفات طالما أنك في حاجة إليها على الفور.
لا أعتقد أن Perl أو awk سيكونان أسرع من Python إذا كنت تقوم فقط بإعادة ترميز الخوارزمية الحالية إلى لغة مختلفة.

awk '/time/{f=0}/subjectB/{f=1;next}f' file
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top