Pandas read_csv для файла размером 6,5 ГБ потребляет более 170 ГБ ОЗУ

Я хотел поднять этот вопрос, просто потому что это безумно странно. Может быть, у Уэса есть какие-то идеи. Файл довольно обычный: 1100 строк x ~3M столбцов, данные разделены табуляцией и состоят исключительно из целых чисел 0, 1 и 2. Очевидно, что этого не ожидается.

Если я предварительно заполню кадр данных, как показано ниже, он потребляет ~ 26 ГБ ОЗУ.

h = open("ms.txt")
header = h.readline().split("\t")
h.close()
rows=1100
df = pd.DataFrame(columns=header, index=range(rows), dtype=int)

Системная информация:

  • питон 2.7.9
  • ипитон 2.3.1
  • 1.9.1
  • панды 0.15.2.

Любые идеи приветствуются.


person Chris F.    schedule 29.01.2015    source источник
comment
Какая это версия Python?   -  person Simeon Visser    schedule 29.01.2015
comment
он действует по-другому, если вы переносите данные? 10^3 рядов и 10^6 кажется... назад.   -  person Paul H    schedule 29.01.2015
comment
что это значит: все данные 0/1/2?   -  person Paul H    schedule 29.01.2015
comment
@PaulH: Вероятно, это означает, что его данные в строках состоят только из 0, 1 и 2.   -  person NullDev    schedule 29.01.2015
comment
@PaulH: извините, именно так. это данные генотипа, буквально символы 0, 1 и 2.   -  person Chris F.    schedule 29.01.2015
comment
Мне любопытно, что такое содержимое ms.txt. Вы вызываете его readline(), что означает, что это многострочный текстовый файл, но затем вы split его. Можете ли вы опубликовать, может быть, первые 10 строк, чтобы быть уверенным?   -  person NullDev    schedule 29.01.2015
comment
@SimeonVisser: Python 2.7.9, ipython 2.3.1, numpy 1.9.1, панды 0.15.2.   -  person Chris F.    schedule 29.01.2015
comment
@TheLaughingMan: это просто для того, чтобы получить информацию заголовка, чтобы указать количество столбцов в данных. Первые три строки данных выглядят так (в numpy): array([[ 0., 0., 0.,..., 0., 0., 0.], [ 1., 1., 0., ..., 1., 0., 0.], [1., 0., 0., ..., 1., 0., 1.],   -  person Chris F.    schedule 29.01.2015
comment
Понятно, значит, это readline, а не readlines. Виноват. Первый, конечно, читает только одну строку. Случайно, какой размер файла ms.txt?   -  person NullDev    schedule 29.01.2015
comment
Сейчас обработка такая: посмотрим, что получится. gist.github.com/cfriedline/9b462b1f4696b2e6dcc3   -  person Chris F.    schedule 29.01.2015
comment
@TheLaughingMan 6,5 ГБ.   -  person Chris F.    schedule 29.01.2015
comment
Это может быть очень наивно, но почему это не правильное воспоминание? Например, если я делаю np.zeros((1100, 3000000)).nbytes / 1e9, я получаю 26.4. Тип dtype — float64.   -  person ely    schedule 29.01.2015
comment
попробуйте сказать read_csv, что все будет целым числом.   -  person Paul H    schedule 29.01.2015
comment
@prpl.mnky.dshwshr: 26,4 ГБ, с которыми я могу справиться, судя по названию этого поста, 170 ГБ — это безумие и странно.   -  person Chris F.    schedule 29.01.2015
comment
Я предполагаю, что вы пытались сделать это следующим образом: with open("ms.txt") as f: header = [x.split("\t") for x in f.readline()] ?   -  person NullDev    schedule 29.01.2015
comment
@TheLaughingMan: посмотрите основную ссылку ;-)   -  person Chris F.    schedule 29.01.2015
comment
Это безумие. Я видел pandas тест производительности раньше с использованием 50 ГБ данных, и я не помню, чтобы он использовал 170 ГБ ОЗУ.   -  person NullDev    schedule 29.01.2015
comment
@TheLaughingMan Согласен. У меня есть коробка с огромной оперативной памятью, на которой я могу это запустить, но, похоже, она не хочет останавливаться. Я убил его вручную на 170GB. Кто знает, насколько большим он мог бы стать?   -  person Chris F.    schedule 29.01.2015
comment
Ну, если я попробую np.zeros((1100, 3000000), dtype=object), он просто зависнет, но я предполагаю, что потребление памяти будет намного выше. Возможно, read_csv делает это и делает несколько копий некоторых вещей, пытаясь распознать типы данных во время чтения?   -  person ely    schedule 29.01.2015
comment
@prpl.mnky.dshwshr возможно. как только я закончу работу, которую мне действительно нужно сделать, я поэкспериментирую с типом данных.   -  person Chris F.    schedule 29.01.2015
comment
Копаясь в материале под read_csv, похоже, что в общем случае он достигает дна с pandas.io.parsers.PythonParser.read, который, кажется, делает копии во время преобразования даты, и в _convert_data, который вызывает _convert_to_ndarrays, который вызывает _convert_types, который затем имеет дополнительные вызовы некоторых функций, таких как maybe_convert_numeric и т. д. , В любом месте этого следа кода вы можете получить увеличение из-за object типа и из-за неэффективного копирования.   -  person ely    schedule 29.01.2015
comment
Чтобы подойти к этому с другой стороны: вручную создав DataFrame 1100x3M dtype int8, общее использование памяти после построения должно составить около ~ 3,1 ГБ, как и ожидалось. В прошлом были углы панд, которые не очень хорошо справляются с ограничениями «много столбцов — несколько строк», так что это также может играть роль.   -  person DSM    schedule 29.01.2015
comment
Спасибо всем, добавление массива numpy int16 составляет чуть менее 7 ГБ, что отлично подходит для моих целей. Рад, что я не совсем сумасшедший. Определенно попробуем dtype в read_csv через некоторое время.   -  person Chris F.    schedule 29.01.2015


Ответы (2)


Проблема вашего примера.

Пробуя ваш код в небольшом масштабе, я заметил, что даже если вы установите dtype=int, вы фактически получите dtype=object в результирующем кадре данных.

header = ['a','b','c']
rows = 11
df = pd.DataFrame(columns=header, index=range(rows), dtype=int)

df.dtypes
a    object
b    object
c    object
dtype: object

Это связано с тем, что даже если вы даете функции pd.read_csv инструкцию о том, что столбцы являются dtype=int, она не может переопределить dtypes, которые в конечном итоге определяются данными в столбце.

Это связано с тем, что панды тесно связаны с numpy и numpy dtypes.

Проблема в том, что в созданном вами кадре данных нет данных, поэтому numpy по умолчанию использует данные как np.NaN, что не помещается в целое число.

Это означает, что numpy запутывается и по умолчанию возвращается к dtype, равному object.

Проблема объекта dtype.

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

Обходной путь для вашего примера.

df = pd.DataFrame(columns=header, index=range(rows), dtype=float)

Это прекрасно работает, так как np.NaN может жить в поплавке. Это производит

a    float64
b    float64
c    float64
dtype: object

И должно занимать меньше памяти.

Подробнее о том, как относиться к dtypes

См. этот связанный пост для получения подробной информации о dtype: Pandas read_csv low_memory и параметры dtype< /а>

person firelynx    schedule 09.02.2015

Аналогичная проблема, с которой я столкнулся сегодня с данными объемом 3 ГБ, и я просто немного изменил свой стиль кодирования, например, вместо методов file.read() и file.readline(), которые я использовал ниже кода, этот код ниже просто загружает 1 строку в время в баране

import re

df_list = []

with open("ms.txt", 'r') as f:
    for line in f:
        #process(line)
        line = line.strip()
        columns = re.split("\t", line, maxsplit=4) # you should modify these according to your split criteria
        df_list.append(columns)

Вот код для преобразования ваших данных в кадр данных pandas.

import pandas as pd
df = pd.DataFrame(df_list)# here you will have to modify according to your data frame needs
person Shubham Sharma    schedule 29.11.2017