Ситуация
У меня есть CSV-файл на 13 миллионов строк, на котором я хочу выполнить логистическую регрессию (инкантер) для каждой группы. Мой файл такой (значения просто образец)
ID Max Probability
1 1 0.5
1 5 0.6
1 10 0.99
2 1 0.1
2 7 0.95
Итак, я сначала прочитал его с помощью csv-reader, все в порядке.
У меня тогда что-то вроде этого:
( {"Id" "1", "Max" 1, "Probability" 0.5} {"Id" "1", "Max" 5, "Probability" 0.6} etc.
Я хочу сгруппировать эти значения по идентификатору. Если я правильно помню, существует около 1,2 миллиона идентификаторов. (Я сделал это на Python с пандами, и это очень быстро)
Это моя функция для чтения и форматирования файла (она отлично работает с небольшими наборами данных):
(defn read-file
[]
(let [path (:path-file @config)
content-csv (take-csv path \,)]
(->> (group-by :Id content-csv)
(map (fn [[k v]]
[k {:x (mapv :Max v) :y (mapv :Probability v)}]))
(into {}))))
Я хочу, наконец, иметь что-то подобное для выполнения логистической регрессии (я гибко отношусь к этому, мне не нужны векторы для :x и :y , последовательности в порядке)
{"1" {:x [1 5 10] :y [0.5 0.6 0.99]} "2" {:x [1 7] :y [0.1 0.95]} etc.
Проблема
У меня проблемы с группировкой. Я попробовал это отдельно на выходе из CSV, и это длится вечно, когда он не умирает из-за памяти Java Heap Space. Я думал, что проблема связана с моей картой, но это group-by.
Я думал об использовании сокращения или сокращения-kv, но я не знаю, как использовать эти функции для таких целей.
Меня не волнует порядок ":x" и ":y" (поскольку они одинаковы между собой, я имею в виду, что x и y имеют одинаковый индекс ... не проблема, потому что они находятся на одном и том же строка) ну и ИДы на конечный результат и я читал, что сгруппировать по порядку. Может быть, это то, что дорого для операции?
Я даю вам образцы данных, если кто-то сталкивался с этим:
(def sample '({"Id" "1" "Max" 1 "Probability" 0.5} {"Id" "1" "Max" 5 "Probability" 0.6} {"Id" "1" "Max" 10 "Probability" 0.99} {"Id" "2" "Max" 1 "Probability" 0.1} {"Id" "2" "Max" 7 "Probability" 0.95}))
Другие варианты
У меня есть другие идеи, но я не уверен, что они совместимы с Clojure.
В Python из-за характера функции и из-за того, что файл уже упорядочен, вместо использования группировки я написал в фрейме данных начальный и конечный индексы для каждой группы, так что мне просто нужно было выбрать непосредственно вложенную вкладку данных.
Я также могу загрузить список идентификаторов вместо того, чтобы вычислять его из Clojure. Нравиться
(def ids '("1" "2" и т.д.
Итак, возможно, можно начать с:
{"1" {:x [] :y []} "2" {:x [] :y []} etc.
из предыдущей последовательности, а затем сопоставьте большой файл с каждым идентификатором.
Я не знаю, действительно ли это эффективнее.
У меня есть все остальные функции для логистической регрессии, только этой части мне не хватает! Спасибо !
ИЗМЕНИТЬ
Спасибо за ответы, наконец-то у меня есть это решение.
В моем файле project.clj
:jvm-opts ["-Xmx13g"])
Код :
(defn data-group->map [group]
{(:Id (first group))
{:x (map :Max group)
:y (map :Probability group)}})
(defn prob-cumsum [data]
(cag/fmap
(fn [x]
(assoc x :y (reductions + (x :y))))
data))
(defn process-data-splitter [data]
(->> (partition-by :Id data)
(map data-group->map)
(into {})
(prob-cumsum)))
Я завернул весь свой код, и он работает. Сплит занимает около 5 минут, но мне не нужна мега-скорость. Использование памяти может доходить до всей памяти для чтения файлов, а затем меньше для сигмоида.