Пролог, прочитайте 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 ;
...
Конечно, отображение строки чтения только для отладки