Пролог, прочитайте CSV-файл и сделайте предикат. найти все

Я использую SWI-Prolog.

У меня есть CSV-файл, где в верхней строке находятся зонды, а затем каждая строка является примером:

    1007_s_at   1053_at 117_at ...
GSM102447.CEL   1   0   0 ...
GSM102449.CEL   1   0   0 ...
GSM102451.CEL   1   0   0 ...
GSM102455.CEL   1   0   0 ...
GSM102507.CEL   1   0   1 ...
...

Фактический файл содержит более 20000 столбцов ("проб") и не более 150 строк ("проб").

Я хочу извлечь каждое отношение и распечатать их как факты в другом файле.

Например:

%probe_value_in_sample(Probe,Sample_Strip,ProbeValue).
probe_value_in_sample('1007_s_at','GSM102447',1).
etc

Мой код до сих пор:

foreach(csv_read_file_row_list('GSE2109_BarCode.csv', List), assert(['samples'|List])).

probe_value_in_sample(Probe,Sample_Strip,ProbeValue):-
[samples|[samples,Empty|ProbeList]],Empty='', %the first value is empty
indexOf(ProbeList,Probe,IndexOfProbe),
[samples|[samples,Sample|SampleValues]],Sample\='',
nth0(IndexOfProbe,SampleValues,ProbeValue),
name(Sample, CharSample),
append(Char_Sample_Strip,".CEL",CharSample),
name(Sample_Strip,Char_Sample_Strip).

%IndexOf(MyList, MyElement, MyIndex).
indexOf([Element|_], Element, 0).
indexOf([_|Tail], Element, Index):-
indexOf(Tail, Element, Index1),
Index is Index1+1.

Это, кажется, работает хорошо, но не работает, или это слишком медленно, чтобы быть непригодным для использования с findall.

Есть идеи, в чем может быть проблема?

Спасибо за любую помощь.

Обновить

Спасибо за ваш ответ.

Я определил:

csv_read_file_row_list(File, List,Functor):-
csv_read_file_row(File,Row,[functor(Functor)]),Row=..List.

Поэтому у меня есть открытый файл, а не поток, и переменная Functor на данный момент излишня.

Я смущен тем, как вы использовали maplist? И я не могу заставить его работать.

Я пытался:

:- dynamic samples/3.

csv_read_file_row_list(File, List,Functor):-
csv_read_file_row(File,Row,[functor(Functor)]),Row=..List.

prepare_db(File) :-
   ( nonvar(File) ; File = 'GSE2109_BarCode.csv' ),
   %open(File, read, S),
   csv_read_file_row_list(File,     ['thing',_Empty|ColKeys],'thing'),
 forall(csv_read_file_row_list(File,    ['thing',RowKeyDirty|Samples],'thing'),
    (   clean_rowkey(RowKeyDirty, RowKey),
        maplist(store_sample(RowKey), ColKeys, Samples)
    )).
%close(S).

store_sample(RowKey, ColKey, Sample) :-
  assertz(samples(RowKey, ColKey, Sample)).

clean_rowkey(RowKeyDirty, RowKey) :- append(RowKey, ".CEL", RowKeyDirty).

Так же как:

:- dynamic samples/3.

csv_read_file_row_list(File, List,Functor):-
csv_read_file_row(File,Row,[functor(Functor)]),Row=..List.

prepare_db(File) :-
( nonvar(File) ; File = 'GSE2109_BarCode.csv' ),
%open(File, read, S),
csv_read_file_row_list(File, ['thing',_Empty|ColKeys],'thing'),
forall(csv_read_file_row_list(File, ['thing',RowKeyDirty|Samples],'thing'),
    (   clean_rowkey(RowKeyDirty, RowKey),
        maplist(store_sample,[RowKey], ColKeys, Samples)
    )).
%close(S).

store_sample(RowKey, ColKey, Sample) :-
assertz(samples(RowKey, ColKey, Sample)).

clean_rowkey(RowKeyDirty, RowKey) :- append(RowKey, ".CEL", RowKeyDirty).

Но оба терпят неудачу.

1 ответ

Решение

Вы не используете assert/1 надлежащим образом. Пролог имеет быструю и эффективную в памяти БД, но, как и любая БД, должен быть правильно проиндексирован. И, конечно же, как любой язык, избегайте повторения одной и той же операции каждый раз, но форматируйте данные один раз при подготовке БД.

:- dynamic samples/3.

prepare_db(File) :-
    ( nonvar(File) ; File = 'GSE2109_BarCode.csv' ),
    open(File, read, S),
    read_row(S, [_Empty|ColKeys]),
    forall(read_row(S, [RowKeyDirty|Samples]),
        (   clean_rowkey(RowKeyDirty, RowKey),
            maplist(store_sample(RowKey), ColKeys, Samples)
        )),
    close(S).

store_sample(RowKey, ColKey, Sample) :-
    assertz(samples(RowKey, ColKey, Sample)).

clean_rowkey(RowKeyDirty, RowKey) :- append(RowKey, ".CEL", RowKeyDirty).

Этот код предполагает, что первая строка имеет то же количество столбцов, что и все остальные строки.

read_row / 2 должен извлечь строку и разбить список списков кодов, я думаю, ваш csv_read_file_row_list/2 уже делает это, но я не могу определить ваше определение в опубликованном коде.

Индексирование лучше работает с атомами, а не со списками кодов. atom_codes/2 позволяет переключаться между этими представлениями.

редактировать

Из вашего комментария и дополнительного размещенного кода я вижу, что мой ответ был не очень уместен. Вот модифицированный и проверенный фрагмент

:- [library(csv)].

:- dynamic samples/3.
:- dynamic column_keys/1.

prepare_db(File) :-
    retractall(column_keys(_)),
    retractall(samples(_,_,_)),
    ( nonvar(File) ; File = '/tmp/test.csv' ),
    forall(read_row(File, Row), store_row(Row)).

store_row(Row) :-
    Row =.. [row|Cols],
    (   column_keys(ColKeys)
    ->  Cols = [RowKeyDirty|Samples],
        clean_rowkey(RowKeyDirty, RowKey),
        maplist(store_sample(RowKey), ColKeys, Samples)
    ;   assertz(column_keys(Cols))
    ).

store_sample(RowKey, ColKey, Sample) :-
    assertz(samples(RowKey, ColKey, Sample)).

clean_rowkey(RowKeyDirty, RowKey) :-
    atom_concat(RowKey, '.CEL', RowKeyDirty).

read_row(File, Row) :-
    csv_read_file_row(File, Row, [separator(0' ), strip(true), convert(true)]),
    writeln(read_row(Row)).

который работает для этого тестового файла

                 1007_s_at    1053_at   117_at
GSM102447.CEL    1            0         0
GSM102449.CEL    1            0         0
GSM102451.CEL    1            0         0
GSM102455.CEL    1            0         0
GSM102507.CEL    1            0         1

и дает

?- prepare_db(_).
read_row(row(1007_s_at,1053_at,117_at))
read_row(row(GSM102447.CEL,1,0,0))
read_row(row(GSM102449.CEL,1,0,0))
read_row(row(GSM102451.CEL,1,0,0))
read_row(row(GSM102455.CEL,1,0,0))
read_row(row(GSM102507.CEL,1,0,1))
true.

16 ?- samples(X,Y,Z).
X = 'GSM102447',
Y = '1007_s_at',
Z = 1 ;
X = 'GSM102447',
Y = '1053_at',
Z = 0 ;
...

Конечно, отображение строки чтения только для отладки

Другие вопросы по тегам