Импортируйте двоичный файл в R, используя typedef struct или numpy - PullRequest
0 голосов
/ 16 мая 2018

У меня есть двоичный файл, который я пытаюсь импортировать в R. Данные, к которым мне нужно получить доступ в этом файле, долго не подписаны (хотя другие типы находятся в файле). Использование readBin () приближается к тому, как должны выглядеть данные, но отличается от того, как должны выглядеть данные:

filepath <- "path/to/file.bin"    
integers <- readBin(con=filepath, what= "int", n=3000, endian="little", signed=FALSE)

Синий - это правильные данные, введенные как CSV, тогда как красный - это вход readBin () в R.

Это выглядит как переполнение из-за целых чисел без знака, которые, к счастью, можно исправить с помощью следующей функции, но она работает только с некоторыми значениями:

int_to_unit <- function (x, adjustment=2^32) {
  x <- as.numeric(x)
  signs <- sign(x)
  x[signs < 0] <- x[signs < 0] + adjustment
  x
}

Исправление для целых чисел без знака почти работает, но только если данные отрицательны.

По сути, проблема в том, что корректировка 2 ^ 32 работает только с данными, которые заканчиваются как отрицательные. Если данные переполняются> 0, я не могу распознать их, чтобы применить исправление. Что еще хуже, некоторые из них переполняются дважды, а может быть, даже больше.

У меня есть структурная функция typedef для C, которую я теоретически мог бы использовать для импорта функции, но я понятия не имею, как это сделать в R.

typedef struct {data definitions I want to use;} dataIwant;

Я исследовал использование python для решения этой проблемы, но, к сожалению, у него точно такая же проблема

import numpy as np
xbash = np.fromfile('/binaryfile.bin', dtype='<I')

Numpy сталкивается с той же проблемой, что и readBin () в R.

Но мне неясно, как поступить. Мои возможные варианты:

  1. Напишите сложный алгоритм для пост-обработки данных,
  2. Вызовите C, чтобы импортировать уникальный тип файла в R, или
  3. Используйте посредническую функцию, написанную на python через сетчатый пакет

Я знаю, что это не типичная проблема для языка R - спасибо, что уделили время для прочтения.

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

У Ральфа Стубнера был правильный ответ, но в нем отсутствовал один элемент, который мог бы помочь, но он был специфичен для двоичных файлов, с которыми я работаю (но в целом для тех, кто надеется прочитать двоичные файлы через C ++ в R).

Проблема заключалась в том, что целочисленные значения в файле, которые были слишком высокими, оборачивались вокруг.

Решением было реализовать код C ++, который предлагал Ральф, но критическидобавить строку для поиска начальной позиции в файле, который имел смысл для данных (file.seekg (число);):

#include <Rcpp.h>
#include <fstream>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector readBinary(std::string fileName, int size) {
    const unsigned long long M = 4294967295LL;
    uint32_t a[size];
    std::ifstream file (fileName, std::ios::in | std::ios::binary);
    if (file.is_open()) {
        file.seekg(513);
        file.read ((char*)&a, sizeof(a));
        file.close();
    }
    NumericVector res(size);
    for (unsigned long long int i = 0; i < size; ++i)
    res(i) = (a[i]) ;
    return res;
}

При добавлении этой строки данныеправильно отображается.

0 голосов
/ 16 мая 2018

Я не считаю этот вопрос нетипичным для R, поскольку R всегда был языком для взаимодействия с кодом, написанным на других языках, таких как Fortan или C. И хотя API C не совсем прост в использовании, он почти тривиален расширить R с помощью кода C ++, используя пакет Rcpp. Генеральный план:

  • Считать данные как целые числа без знака подходящего размера, например, uint32_t
  • Преобразовать в двойники
  • Возврат как Rcpp::NumericVector
  • Используйте Rcpp::sourceCpp, чтобы сделать функцию доступной в R

Подробнее см. виньетка атрибутов Rcpp .

Редактировать: Вот пример кода для приведенной выше идеи:

#include <Rcpp.h>
#include <fstream>
using namespace Rcpp;

// [[Rcpp::export]]
void writeBinary(std::string fileName, NumericVector data) {
  int size = data.size();
  int32_t a[size];
  for (int i = 0; i < size; ++i)
    a[i] = static_cast<uint32_t>(data(i));
  std::ofstream file(fileName, std::ios::out | std::ios::binary);
  if (file.is_open()) {
    file.write ((char*)&a, sizeof(a));
    file.close();
  }
}


// [[Rcpp::export]]
NumericVector readBinary(std::string fileName, int size) {
  uint32_t a[size];
  std::ifstream file (fileName, std::ios::in | std::ios::binary);
  if (file.is_open()) {
    file.read ((char*)&a, sizeof(a));
    file.close();
  }
  NumericVector res(size);
  for (int i = 0; i < size; ++i)
    res(i) = a[i];
  return res;
}


/*** R
fileName <- tempfile()
N <- 10
data <- sample(seq_len(2^32 - 1), N)
writeBinary(fileName, data)
all.equal(data, readBinary(fileName, N))
*/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...