Экспорт в файлы CSV в Julia

Предупреждение: это вопросы новичков, так как я действительно новичок в Джулии.

В R есть довольно унифицированная функция для экспорта (почти) любого объекта с read.table(). Похоже, у Юлии дела обстоят немного сложнее. Если я хорошо понимаю:

  1. Некоторые стандартные типы (например, массивы, словари и кортежи) всегда можно экспортировать с writedlm, но не всегда с CSV.write. И наоборот, DataFrames всегда можно экспортировать с CSV.write, но никогда с writedlm. Это верно? Таким образом, не существует универсального экспортера в том же смысле, что и write.table()?

  2. Помимо записи файла CSV, CSV.write, похоже, также возвращает имя экспортированного файла. И наоборот, writedlm нет. Для меня это проблема. На самом деле мне понадобится способ экспортировать DataFrame в файл CSV с функцией, которая не возвращает значение, то есть функцию, которая имеет только побочные эффекты, например writedlm. Есть ли способ добиться этого в Юлии?

    РЕДАКТИРОВАТЬ: чтобы углубиться в подробности, моя проблема в том, что после CSV.write ans указывает на имя экспортированного файла; а с writedlm дело обстоит иначе. Иллюстрация здесь и здесь. Даже с идеей, предложенной @Przemyslaw Szufel, я не могу избавиться от этого. (Это довольно тонкая проблема, но я на самом деле пытаюсь написать бэкэнд emacs lisp для Джулии. Несоответствия такого рода, например, незнание, будет ли ans nothing или имя файла после экспорта объекта, добавляет некоторую боль в этом приключения ... :-) В идеале, я просто хотел, чтобы CSV.write мог молчать.)

Спасибо!


person Philopolis    schedule 08.10.2020    source источник


Ответы (1)


Я начинаю со второго вопроса, потому что он короткий. Просто используйте точку с запятой ; в конце строки, и значение не будет возвращено!

CSV.write(file, table);

Однако, если вы хотите быть уверены, что ans не имеет значения, добавьте nothing в конце:

CSV.write(file, table);nothing;

если хотите, можете упаковать его в функцию:

function my_write(file, table)
    CSV.write(file, table)
    nothing
end

Или, если вы хотите, чтобы однострочник обернул его в лямбду:

julia> (() -> begin;CSV.write("file.csv", df);nothing;end)()

julia> ans == nothing
true

В каждом случае побочного эффекта (возвращаемого значения) не наблюдается.

Первый вопрос посложнее. Очевидно, что возможные форматы, используемые для хранения данных в файле, должны зависеть от формата данных. В основном наиболее распространенные варианты для Джулии включают (я начинаю с самых общих и заканчиваю самыми конкретными):

  • сериализация с помощью команды serialize
  • двоичный JSON через пакет BSON.jl
  • JSON через JSON.jl или чуть более новый пакет JSON3.jl (на сегодняшний день оба являются хорошим выбором)
  • JSONTables.jl для табличных данных, хранящихся в формате JSON
  • DelimitedFiles для хранения Arrays
  • CSV.jl для хранения DataFrames

Теперь выбор того или иного пакета будет зависеть от вашей цели. Сериализация - убийственный механизм - самый быстрый и универсальный. Таким образом можно сохранить любой объект в кратчайшие сроки. Ничто не обходится без затрат - когда вы обновляете версию Julia или свои пакеты, вы, возможно, не сможете прочитать свой объект обратно. Так что он рассчитан на кратковременное хранение.

В середине ставки находятся системы хранения на основе JSON. По сути, все может быть сохранено в формате JSON и может быть прочитано позже на Julia или других языках программирования. Текстовый JSON также можно открыть в простом текстовом редакторе.

Наконец, CSV.jl и Serialization можно использовать для таблиц и массивов соответственно. Однако легко преобразовать DataFrame в Array или Array в DataFrame:

julia> df = DataFrame(a=1:3, b=rand(3),c=["a","b","c"])
3×3 DataFrame
│ Row │ a     │ b        │ c      │
│     │ Int64 │ Float64  │ String │
├─────┼───────┼──────────┼────────┤
│ 1   │ 1     │ 0.440796 │ a      │
│ 2   │ 2     │ 0.44232  │ b      │
│ 3   │ 3     │ 0.282064 │ c      │

julia> Matrix(df)
3×3 Array{Any,2}:
 1  0.440796  "a"
 2  0.44232   "b"
 3  0.282064  "c"

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

Обратное преобразование также просто:

julia> rand(3,3) |> Tables.table |> DataFrame
3×3 DataFrame
│ Row │ Column1  │ Column2   │ Column3  │
│     │ Float64  │ Float64   │ Float64  │
├─────┼──────────┼───────────┼──────────┤
│ 1   │ 0.326649 │ 0.0278134 │ 0.111221 │
│ 2   │ 0.769378 │ 0.996156  │ 0.237821 │
│ 3   │ 0.802094 │ 0.726497  │ 0.619013 │

В заключение, как видите, все можно сделать в Юлии.

person Przemyslaw Szufel    schedule 08.10.2020
comment
Большое спасибо за отличный ответ! У моего первого вопроса теперь есть идеальное объяснение, у меня есть все, что мне сейчас нужно ;-) Однако, похоже, что мой второй вопрос сложнее, чем я думал ... Я отредактировал свой исходный пост, добавив больше деталей и примеров. - person Philopolis; 08.10.2020
comment
Два небольших комментария к этому замечательному ответу: 1) CSV.jl предназначен для таблиц в целом, а не только для DataFrame. 2) В общем, преобразование матрицы в таблицу должно выполняться с использованием функции Tables.table (поскольку разные матрицы по-разному специализируются на том, как они ожидают обработки в качестве таблицы + Tables.table не выделяет память). - person Bogumił Kamiński; 08.10.2020