Чтение файла .dat в Julia, проблемы с переменным интервалом разделителя - PullRequest
2 голосов
/ 07 мая 2020

У меня проблемы с чтением файла .dat в фрейм данных. Думаю, проблема в разделителе. Я добавил снимок экрана, показывающий, как выглядят данные в файле ниже. Я предполагаю, что это разделитель табуляции между столбцами, а затем разделитель новой строки между строками. Я пробовал читать данные с помощью следующих команд:

    df = CSV.File("FORCECHAIN00046.dat"; header=false) |> DataFrame!
    df = CSV.File("FORCECHAIN00046.dat"; header=false, delim = ' ') |> DataFrame!

Мой результат в любом случае - это просто DataFrame с одним столбцом, включающим все данные из каждого столбца, объединенные в одну строку. Я попытался даже указать типы с помощью следующего кода:

df = CSV.File("FORCECHAIN00046.dat"; types=[Float64,Float64,Float64,Float64,
Float64,Float64,Float64,Float64,Float64,Float64,Float64,Float64]) |> DataFrame!

И я получил следующую ошибку:

┌ Warning: 2; something went wrong trying to determine row positions for multithreading; it'd be very helpful if you could open an issue at https://github.com/JuliaData/CS
V.jl/issues so package authors can investigate

Я могу обойти это, загрузив его в таблицы Google и затем загрузите csv, но я хотел бы найти способ заставить исходный файл .dat работать.

enter image description here

1 Ответ

2 голосов
/ 07 мая 2020

Частично проблема здесь в том, что .dat не является правильным форматом файла - это просто что-то, что, кажется, записано в несколько удобочитаемом формате со столбцами чисел, разделенными переменным количеством пробелов, так что числа выстраиваются в линию, когда вы смотрите на них в редакторе. В Google Таблицах встроено множество хитрых приемов, позволяющих «делать то, что вы хотите» для всех видов плохо определенных файлов данных, поэтому я не слишком удивлен, что ему удается это проанализировать. Пакет CSV, с другой стороны, поддерживает использование одного символа в качестве разделителя или даже многосимвольной строки, но не переменного количества пробелов, подобных этому.

Возможные решения:

  • если файлы не слишком большие, вы можете легко создать собственный синтаксический анализатор, который разбивает каждую строку, а затем строит матрицу
  • вы также можете предварительно обработать файл, превратив несколько пробелов в отдельные пробелы

Это, вероятно, самый простой способ сделать это, и вот код Джулии (непроверенный, поскольку вы не предоставили тестовые данные), который откроет ваш файл и преобразует его в более разумный формат:

function dat2csv(dat_path::AbstractString, csv_path::AbstractString)
    open(csv_path, write=true) do io
        for line in eachline(dat_path)
            join(io, split(line), ',')
            println(io)
        end
    end
    return csv_path
end

function dat2csv(dat_path::AbstractString)
    base, ext = splitext(dat_path)
    ext == ".dat" ||
        throw(ArgumentError("file name doesn't end with `.dat`"))
    return dat2csv(dat_path, "$base.csv")
end

Вы могли бы вызвать эту функцию как dat2csv("FORCECHAIN00046.dat"), и она создаст файл FORCECHAIN00046.csv, который будет правильным файлом CSV с использованием запятых в качестве разделителей. Это не сработает, если файлы содержат какие-либо значения с запятыми, но похоже, что это просто числа, и в этом случае все должно быть в порядке. Таким образом, вы можете использовать эту функцию для преобразования файлов в правильный CSV, а затем загрузить этот файл с помощью пакета CSV.

Небольшое объяснение кода:

  • двухаргументный dat2csv метод открывает csv_path для записи, а затем вызывает eachline на dat_path для чтения одной строки из нее за раз
  • eachline удаляет любую завершающую новую строку из каждой строки, поэтому каждая line будет набор чисел, разделенных пробелами с некоторыми ведущими и / или конечными пробелами.
  • split(line) выполняет разделение по умолчанию line, которое разбивает его на пробелы, отбрасывая любые пустые значения - это оставляет только не- записи пробелов в виде строк в массиве
  • join(io, split(line), ',') объединяет строки в массиве вместе, разделенные символом ,, и записывает это в дескриптор записи io для csv_path
  • println(io) записывает новую строку после этого - иначе все просто оказалось бы в одной очень длинной строке
  • метод с одним аргументом dat2csv вызывает splitext, чтобы разделить имя файла на базовый e имя и расширение, проверяя, является ли расширение ожидаемым .dat, и вызывая версию с двумя аргументами с заменой .dat на .csv
...