Похоже, что с помощью Google должно быть ДЕЙСТВИТЕЛЬНО легко ответить, но я считаю, что таким образом невозможно ответить на большинство моих нетривиальных вопросов о pandas/pytables. Все, что я пытаюсь сделать, это загрузить около 3 миллиардов записей из примерно 6000 различных файлов CSV в одну таблицу в одном файле HDF5. Это простая таблица, 26 полей, смесь строк, чисел с плавающей запятой и целых чисел. Я загружаю CSV с помощью df = pandas.read_csv()
и добавляю их в свой файл hdf5 с помощью df.to_hdf()
. Я действительно не хочу использовать df.to_hdf(data_columns = True)
, потому что похоже, что это займет около 20 дней против примерно 4 дней для df.to_hdf(data_columns = False)
. Но, очевидно, когда вы используете df.to_hdf(data_columns = False)
, вы получаете кучу мусора, из которого вы даже не можете восстановить структуру таблицы (по крайней мере, так кажется на мой неподготовленный взгляд). Только столбцы, которые были определены в списке min_itemsize (4 строковых столбца), можно идентифицировать в таблице hdf5, остальные выгружаются по типу данных в values_block_0
–values_block_4
:
table = h5file.get_node('/tbl_main/table')
print(table.colnames)
['index', 'values_block_0', 'values_block_1', 'values_block_2', 'values_block_3', 'values_block_4', 'str_col1', 'str_col2', 'str_col3', 'str_col4']
И любой запрос, например df = pd.DataFrame.from_records(table.read_where(condition))
, завершается с ошибкой «Исключение: данные должны быть одномерными».
Итак, мои вопросы: (1) Мне действительно нужно использовать data_columns = True
, который занимает в 5 раз больше времени? Я ожидал выполнить быструю загрузку, а затем проиндексировать всего несколько столбцов после загрузки таблицы. (2) Что это за куча мусора, которую я использую data_columns = False
? Будет ли это хорошо, если мне нужна моя таблица обратно со столбцами, доступными для запросов? Это вообще на что-то годится?
Я думал, что это общий вопрос о data_columns = True и False ... что-то, что должно быть хорошо освещено в документации pytables, но, насколько я могу судить, это не так.
Не уверен, почему pytbales dos должен покрывать это. df.to_hdf(data_columns = True)
против False
— это функция панд. Если все ваши файлы CSV имеют одинаковые столбцы данных, и все, что вам нужно, это файл HDF5 с одним и тем же файлом, возможно, вам следует пропустить pandas и вместо этого использовать pytables или h5py. Есть ТАК ответы о том, как это сделать.
Правильно, я исправлен, должен был сказать документацию pandas. Я потратил довольно много времени на просмотр pytables, чтобы пропустить шаг read_csv кадра данных, но не смог получить скорость read_csv вместе с богатством того, что read_csv может делать во время чтения. Но если pytables намного быстрее, я бы согласился просто сосать CSV без какой-либо причудливой обработки. Итак, никто ничего не знает о df.to_hdf(data_columns = True vs False)? Одна из величайших тайн жизни?
Я собирался указать вам на мой ответ на предыдущий вопрос об этом. Затем я обнаружил, что «вопрос был добровольно удален его автором». Я нашел свой старый код и изменил его, чтобы решить вашу ситуацию с несколькими CSV. Смотрите ответ ниже.
Вот как вы можете создать файл HDF5 из данных CSV с помощью pytables. Вы также можете использовать аналогичный процесс для создания файла HDF5 с помощью h5py.
np.genfromtxt
в массив np..create_table()
, ссылаясь на массив np, созданный на шаге 1..append()
, ссылаясь на массив np, созданный на шаге 1.Конец цикла
Обновлено 02.06.2019 для чтения поля даты (мм/дд/ГГГ) и преобразования в объект datetime
. Обратите внимание на изменения в аргументах genfromtxt()
! Используемые данные добавляются под обновленным кодом.
import numpy as np
import tables as tb
from datetime import datetime
csv_list = ['SO_56387241_1.csv', 'SO_56387241_2.csv' ]
my_dtype= np.dtype([ ('a',int),('b','S20'),('c',float),('d',float),('e','S20') ])
with tb.open_file('SO_56387241.h5', mode='w') as h5f:
for PATH_csv in csv_list:
csv_data = np.genfromtxt(PATH_csv, names=True, dtype=my_dtype, delimiter=',', encoding=None)
# modify date in fifth field 'e'
for row in csv_data :
datetime_object = datetime.strptime(row['my_date'].decode('UTF-8'), '%m/%d/%Y' )
row['my_date'] = datetime_object
if h5f.__contains__('/CSV_Data') :
dset = h5f.root.CSV_Data
dset.append(csv_data)
else:
dset = h5f.create_table('/','CSV_Data', obj=csv_data)
dset.flush()
h5f.close()
Данные для тестирования:
SO_56387241_1.csv:
my_int,my_str,my_float,my_exp,my_date
0,zero,0.0,0.00E+00,01/01/1980
1,one,1.0,1.00E+00,02/01/1981
2,two,2.0,2.00E+00,03/01/1982
3,three,3.0,3.00E+00,04/01/1983
4,four,4.0,4.00E+00,05/01/1984
5,five,5.0,5.00E+00,06/01/1985
6,six,6.0,6.00E+00,07/01/1986
7,seven,7.0,7.00E+00,08/01/1987
8,eight,8.0,8.00E+00,09/01/1988
9,nine,9.0,9.00E+00,10/01/1989
SO_56387241_2.csv:
my_int,my_str,my_float,my_exp,my_date
10,ten,10.0,1.00E+01,01/01/1990
11,eleven,11.0,1.10E+01,02/01/1991
12,twelve,12.0,1.20E+01,03/01/1992
13,thirteen,13.0,1.30E+01,04/01/1993
14,fourteen,14.0,1.40E+01,04/01/1994
15,fifteen,15.0,1.50E+01,06/01/1995
16,sixteen,16.0,1.60E+01,07/01/1996
17,seventeen,17.0,1.70E+01,08/01/1997
18,eighteen,18.0,1.80E+01,09/01/1998
19,nineteen,19.0,1.90E+01,10/01/1999
Этот подход выглядит многообещающе... например, я могу делать все, что делал с read_csv, используя вместо этого genfromtxt, и это может иметь ожидаемую скорость. Но, будучи невежественным, я не могу понять, как читать строковые поля. И мне не разрешено вводить здесь достаточно символов, чтобы показать, что я делаю. Думаю, я попытаюсь отредактировать исходный пост выше...
Не могу понять, как добавить свой код в редактирование... что мне делать, начать новый вопрос в новой теме "genfromtxt"?
Отмените это, в четвертый раз, когда я попробовал синтаксис типа «| S10», он наконец сработал. Сейчас пытаюсь разобраться с преобразователями строк в целые и преобразованием даты...
Что вы подразумеваете под «не могу понять, как читать строковые поля»? Когда вы используете dtype=None
, genfromtxt
должен автоматически создавать dtype на основе найденных данных. Затем create_table
будет использовать dtype массива np для определения типов данных полей таблицы. Кроме того, помните, что вы имеете дело с объектами Unicode. Я не знаю, что произойдет, если в каждой строке у вас есть строковые поля разной длины. Кроме того, если вы знаете формат файла CSV, вы можете определить dtype и ссылку в genfromtxt
.
Я должен определить dtypes в виде списка, иначе «догадки» в более ранних CSV-файлах будут неправильными для более поздних CSV-файлов. Но даже если бы мне этого не нужно было делать, dtype = None дает мусор для строковых полей. На данный момент я отказываюсь от всех своих преобразователей и пытаюсь жить ни с одним из них, кроме дат.
Хорошо, у меня действительно работают все мои конвертеры, кроме дат. Данные имеют формат «мм/дд/гггг», и я думаю, что хочу преобразовать их в np.datetime64 (но я возьму все, что смогу). Я пытаюсь {'date': lambda s : np.datetime64(s, 's')} и еще дюжину вариаций на этот счет и другие вещи, найденные в Google, но без любви. Любые подсказки?
Что ж, мой проект еще не сдвинулся с мертвой точки, но похоже, что базовый код kcw78 будет работать, чтобы получить что-то похожее на версию для панд при сохранении скорости ... поэтому я отмечу как ответ. Последний комментарий: флаг «w» у меня не работает, мне нужен «a», иначе файл hdf5 воссоздается в каждом цикле вместо добавления.
Режим «w» и «a» зависит от порядка открытия файла HDF5 и чтения файлов CSV. Я зацикливаюсь внутри CSV внутри with
, который создает/открывает файл HDF5. Разная логика может привести к разному поведению.
Давайте посмотрим, сможем ли мы решить ваши проблемы с датой и временем. Констатация очевидного: формат ваших дат зависит от того, что вы хотите с ними делать. Строки хороши, если вы просто хотите печатать. datetime
ожидает ввода строки, поэтому обработка зависит от типа данных, который вы получили от genfromtxt
. Из моего тестирования по умолчанию возвращается юникод. Однако вы можете определить свой dtype для чтения в виде строк. Я изменил код в своем ответе, чтобы показать, как вы можете это сделать. Кроме того, я добавил данные, используемые в примере. Надеюсь это поможет.
Спасибо за дополнительный вклад. Я долго думал над проблемой преобразования даты и решил, что лучше всего преобразовать в YYYYMMDD int32. Это столбцы, которые необходимо индексировать, и мне не нравится тип даты и времени Python, так как мне нужна кроссплатформенность.
Чтобы преобразовать форматы даты и времени, проверьте datetime strftime()
. Вы предоставляете объект datetime и формат вывода. Добавьте int()
, если вам это нужно. Добавьте что-то вроде этого в код выше: dt_ymd = int(datetime.datetime.strftime(datetime_object , '%Y%m%d'))
Это полезно, но предполагается, что у меня есть объект datetime... это было легко использовать с пандами, потому что я мог использовать аргументы infer_datetime_format и parse_dates в методе read_csv, но я еще не нашел способа сделать это в рамках капот с numpy.genfromtxt ... есть ли способ? То, как я это делаю сейчас, использует грубую силу с пользовательским преобразователем, который берет строку байтов и делает dt = datetime.strptime(byte_str.decode("UTF-8"), '%m/%d/%Y' ) ... вероятно, очень медленный по сравнению с методом панд.
dts, да, я использовал объект datetime, который создал в своем ответе. Я нашел SO Q&A, который считывает объект datetime, определяя dtype
и добавляя converters = {0:datefunc}
к numpy.genfromtxt
. Смотрите это: numpy-unicodedecodeerror-am-я-использую-правильный-подход-с-genfromtxt
В этой ссылке есть почти то, что я делаю (конвертер). На самом деле это работает довольно хорошо, я закончил загрузку всех своих данных в 2 больших файла hdf5, и это заняло всего 4 дня.
Хорошая работа. Итак, это примерно так же быстро, как df.to_hdf(data_columns = False)
и намного быстрее, чем df.to_hdf(data_columns = True)
, и вы закончите, прежде чем умрете от старости. :-) Хороший.
Правильно ... и большое спасибо за всю вашу помощь, это было неоценимо.
Эй, дтс! Этот вопрос потребует некоторого редактирования, прежде чем кто-либо сможет ответить на него. Одно из основных правил — задавать по 1 конкретному вопросу за раз, так что вас, скорее всего, за это пометят. Кроме того, отображение минимальный воспроизводимый пример правильного и искаженного результата на некоторых небольших кадрах данных поможет любому читателю понять, как помочь.