Каков наиболее эффективный способ импорта таблицы с открытым текстом в виде куба данных, где срезы определяются тем, где изменяется значение одного столбца?

#python #numpy

Вопрос:

У меня есть файл данных, содержащий эволюцию спектра с течением времени. Я могу загрузить данные np.loadtxt , но это возвращает 2D-массив с 3 столбцами — точное представление файла, но не лучшая структура для циклического перебора через каждый интервал времени. Я хотел бы преобразовать данные в куб, где каждый срез содержит спектр за один раз.

Входной файл выглядит следующим образом:

 Time    Wavelength    Flux
1.0     100           30
1.0     101           29
1.0     102           31
...
1.0     200           43
2.0     100           30
2.0     101           29.5
...
2.0     200           42
3.0     100           31
3.0     101           32
...
100     200           37
 

np.loadtxt возвращает массив n x 3, где n-количество строк в файле. Я хотел бы, чтобы мой код сформировал данные в куб, используя строки, в которых столбец времени увеличивается как точки останова. Другими словами, я хотел бы иметь список спектров, где каждый спектр на один шаг позже предыдущего. Вот визуальная репрезентация того, что я имею в виду.

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

Есть ли более быстрый, более питонический способ сделать это? Или это единственный работоспособный способ каждый раз перебирать файл, чтобы вручную определить точки останова?

Комментарии:

1. Если количество строк на шаг по времени в данном файле постоянно, и вы можете легко определить количество шагов по времени в файле, то вы сможете использовать это, numpy.reshape чтобы получить нужную форму.

Ответ №1:

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

Независимо от того, насколько точно вы знаете, сколько у вас их, вы могли бы использовать numpy.split в своем массиве, чтобы разделить свой массив на блоки одного и того же времени.

В более грубой силе, но, возможно , лучше, если количество строк с одинаковым временем варьируется, вы можете разделить их с помощью for цикла и numpy.append создать подмассивы с одинаковым временем.

Редактировать

Исходя из того, что вы дали, вам в основном нужно знать, сколько строк из временных шагов у вас есть из каждого файла.

Так как у меня нет ваших данных, я создаю искусственный каталог_данных для примера

 import numpy as np

length=np.random.randint(6,9)

artificial_data = np.transpose((np.concatenate((np.ones(length),2*np.ones(length),3*np.ones(length),4*np.ones(length))),
              np.concatenate((np.random.rand(length),np.random.rand(length),np.random.rand(length),np.random.rand(length))),
              np.concatenate((np.random.rand(length),np.random.rand(length),np.random.rand(length),np.random.rand(length)))))

artificial_data
 

что дает (это случайные числа, поэтому они будут меняться при каждом запуске )

 array([[1.        , 0.62337349, 0.84582971],
       [1.        , 0.38484415, 0.57365805],
       [1.        , 0.80504472, 0.67706586],
       [1.        , 0.49799682, 0.69909408],
       [1.        , 0.06563674, 0.51799158],
       [1.        , 0.65680522, 0.7616487 ],
       [1.        , 0.11497811, 0.67833476],
       [2.        , 0.74605054, 0.40117761],
       [2.        , 0.47544047, 0.40270957],
       [2.        , 0.79241801, 0.92569317],
       [2.        , 0.69839158, 0.21629401],
       [2.        , 0.7169591 , 0.32631124],
       [2.        , 0.8832162 , 0.55114389],
       [2.        , 0.91455405, 0.28574292],
       [3.        , 0.61089879, 0.77563826],
       [3.        , 0.15776237, 0.64906268],
       [3.        , 0.80971068, 0.76695185],
       [3.        , 0.88994052, 0.07681381],
       [3.        , 0.71479789, 0.50768739],
       [3.        , 0.56042634, 0.25032607],
       [3.        , 0.44866057, 0.54832829],
       [4.        , 0.2643985 , 0.62251815],
       [4.        , 0.21353805, 0.91354626],
       [4.        , 0.75809504, 0.71601593],
       [4.        , 0.84296248, 0.87818252],
       [4.        , 0.95029666, 0.10553645],
       [4.        , 0.42500662, 0.92322183],
       [4.        , 0.95176257, 0.63409806]])
 

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

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

 num_of_time_steps = int(max(np.transpose(artificial_data)[0]))
separated_data = np.split(np.transpose(np.transpose(artificial_data)[1:]),num_of_time_steps)
separated_data
 

что дает желаемый результат

 [array([[0.62337349, 0.84582971],
        [0.38484415, 0.57365805],
        [0.80504472, 0.67706586],
        [0.49799682, 0.69909408],
        [0.06563674, 0.51799158],
        [0.65680522, 0.7616487 ],
        [0.11497811, 0.67833476]]),
 array([[0.74605054, 0.40117761],
        [0.47544047, 0.40270957],
        [0.79241801, 0.92569317],
        [0.69839158, 0.21629401],
        [0.7169591 , 0.32631124],
        [0.8832162 , 0.55114389],
        [0.91455405, 0.28574292]]),
 array([[0.61089879, 0.77563826],
        [0.15776237, 0.64906268],
        [0.80971068, 0.76695185],
        [0.88994052, 0.07681381],
        [0.71479789, 0.50768739],
        [0.56042634, 0.25032607],
        [0.44866057, 0.54832829]]),
 array([[0.2643985 , 0.62251815],
        [0.21353805, 0.91354626],
        [0.75809504, 0.71601593],
        [0.84296248, 0.87818252],
        [0.95029666, 0.10553645],
        [0.42500662, 0.92322183],
        [0.95176257, 0.63409806]])]
 

Теперь вы можете обрабатывать все данные с заданного временного шага по первому индексу разделенных данных как

 data_with_time_step_i = separated_data[i]
 

Надеюсь, это вам поможет, я не мог бы придумать ничего проще, чем это

Комментарии:

1. Количество строк на шаг времени должно быть одинаковым в каждом файле, но я буду запускать этот код в разных файлах, каждый из которых может содержать разное количество строк на шаг времени.