улучшить отображаемые lambdas в Python (панды)

Я перевариваю несколько файлов csv (каждый с одним или несколькими годами данных), чтобы классифицировать медицинские процедуры в широкие категории, а также хранить только подмножество исходной информации и даже суммировать до ежемесячного числа (по AR = год и месяц ) лечения на одного человека (LopNr). Многие обращения относятся к разным категориям одновременно (несколько кодов диагностики указаны в соответствующем столбце в csv, поэтому я разделяю это поле на столбец списков и классифицирую строки по кодам диагностики, принадлежащим к соответствующему диапазону ICD-9 коды).

Я использую IOPro для сохранения в памяти, но я все еще сталкиваюсь с segfault (все еще исследуя). Текстовые файлы имеют по несколько ГБ каждый, но этот аппарат имеет 256 ГБ оперативной памяти. Либо один из пакетов неисправен, или мне нужно более эффективное решение с памятью.

Я использую версии pandas 0.16.2 np19py26_0, iopro 1.7.1 np19py27_p0 и python 2.7.10 0 под Linux.

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

LopNr AR INDATUMA DIAGNOS … 1 2007 20070812 C32 F17 1 2007 20070816 C36 

И я надеюсь увидеть такие агрегаты:

 LopNr AR month tobacco … 1 2007 8 2 

Кстати, мне нужны файлы Stata dta в конце, но я прохожу через cvs, потому что pandas.DataFrame.to_stata кажутся немного шелушащимися в моем опыте, но, возможно, я тоже там что-то не хватает.

 # -*- coding: utf-8 -*- import iopro import numpy as np from pandas import * all_treatments = DataFrame() filelist = ['oppenvard20012005','oppenvard20062010','oppenvard2011','oppenvard2012','slutenvard1997','slutenvard2011','slutenvard2012','slutenvard19982004','slutenvard20052010'] tobacco = lambda lst: any( (((x >= 'C30') and (x<'C40')) or ((x >= 'F17') and (x<'F18'))) for x in lst) nutrition = lambda lst: any( (((x >= 'D50') and (x<'D54')) or ((x >= 'E10') and (x<'E15')) or ((x >= 'E40') and (x<'E47')) or ((x >= 'E50') and (x<'E69'))) for x in lst) mental = lambda lst: any( (((x >= 'F') and (x<'G')) ) for x in lst) alcohol = lambda lst: any( (((x >= 'F10') and (x<'F11')) or ((x >= 'K70') and (x<'K71'))) for x in lst) circulatory = lambda lst: any( (((x >= 'I') and (x<'J')) ) for x in lst) dental = lambda lst: any( (((x >= 'K02') and (x<'K04')) ) for x in lst) accident = lambda lst: any( (((x >= 'V01') and (x<'X60')) ) for x in lst) selfharm = lambda lst: any( (((x >= 'X60') and (x<'X85')) ) for x in lst) cancer = lambda lst: any( (((x >= 'C') and (x<'D')) ) for x in lst) endonutrimetab = lambda lst: any( (((x >= 'E') and (x<'F')) ) for x in lst) pregnancy = lambda lst: any( (((x >= 'O') and (x<'P')) ) for x in lst) other_stress = lambda lst: any( (((x >= 'J00') and (x<'J48')) or ((x >= 'L20') and (x<'L66')) or ((x >= 'K20') and (x<'K60')) or ((x >= 'R') and (x<'S')) or ((x >= 'X86') and (x<'Z77'))) for x in lst) for file in filelist: filename = 'PATH' + file +'.txt' adapter = iopro.text_adapter(filename,parser='csv',field_names=True,output='dataframe',delimiter='\t') treatments = adapter[['LopNr','AR','DIAGNOS','INDATUMA']][:] treatments['month'] = treatments['INDATUMA'] % 10000 treatments['day'] = treatments['INDATUMA'] % 100 treatments['month'] = (treatments['month']-treatments['day'])/100 del treatments['day'] diagnoses = treatments['DIAGNOS'].str.split(' ') del treatments['DIAGNOS'] treatments['tobacco'] = diagnoses.map(tobacco) treatments['nutrition'] = diagnoses.map(nutrition) treatments['mental'] = diagnoses.map(mental) treatments['alcohol'] = diagnoses.map(alcohol) treatments['circulatory'] = diagnoses.map(circulatory) treatments['dental'] = diagnoses.map(dental) treatments['accident'] = diagnoses.map(accident) treatments['selfharm'] = diagnoses.map(selfharm) treatments['cancer'] = diagnoses.map(cancer) treatments['endonutrimetab'] = diagnoses.map(endonutrimetab) treatments['pregnancy'] = diagnoses.map(pregnancy) treatments['other_stress'] = diagnoses.map(other_stress) all_treatments = all_treatments.append(treatments) all_treatments = all_treatments.groupby(['LopNr','AR','month']).aggregate(np.count_nonzero) #.sum() all_treatments = all_treatments.astype(int,copy=False,raise_on_error=False) all_treatments.to_csv('PATH.csv') 

2 Solutions collect form web for “улучшить отображаемые lambdas в Python (панды)”

Я думаю, вам нужно найти способ для векторизации вашего решения. Использование map и лямбда-функций неэффективно и не использует ускорения, которые делают панды настолько полезными. Трудно сказать наверняка, потому что вы не разместили образцы данных, но я думаю, что хорошей отправной точкой было бы сделать

 diagnoses = treatments['DIAGNOS'].str.split(expand=True) 

Результатом будет кадр данных со столбцом для каждого слова (или элемента в результате разделения). Затем вы можете провести векторизованные сопоставления со всем DataFrame. Это может выглядеть примерно так:

 between_c_vals = (diagnoses >= 'C30') & (diagnoses <= 'C40') between_f_vals = (diagnoses >= 'F17') & (diagnoses <= 'F18') treatment['tobacco'] = (between_c_vals | between_f_vals).any(axis=1) 

Это должно быть в сотни раз быстрее, чем использование .map которое использует петли в Python. Заметим, что операторы бит & и | может использоваться для выполнения заданной логики на булевых векторах и матрицах (или в DataFrames). Если вы показали пример treatment['DIAGNOS'] я мог бы помочь больше. Одна вещь, о которой нужно быть осторожным, – это значения NaN при сравнении, когда сравнение NaN с чем угодно всегда возвращает False но я думаю, что должно быть хорошо, что он не вернет никаких нежелательных True значений.

Несколько комментариев:

  1. Как отмечалось выше, вы должны упростить свои лямбда-выражения для удобства чтения, возможно, используя def .

Пример:

 def tobacco(codes): return any( 'C30' <= x < 'C40' or 'F17' <= x < 'F18' for x in codes) 

Вы можете также векторизовать эти функции следующим образом:

 def tobacco(codes_column): return [any('C30' <= code < 'C40' or 'F17' <= code < 'F18' for code in codes) if codes else False for codes in codes_column] diagnoses = all_treatments['DIAGNOS'].str.split(' ').tolist() all_treatments['tobacco'] = tobacco(diagnoses) 
  1. Вы инициализируете all_treatments в DataFrame, а затем добавляете к нему. Это очень неэффективно. Попробуйте all_treatments = list() и добавьте all_treatments = pd.concat(all_treatments, ignore_index=True) вне цикла непосредственно перед вашей groupby . Кроме того, это должно быть all_treatments.append(treatments) (vs. all_treatments = all_treatments.append(treatments) )

  2. Чтобы рассчитать месяц для целей группировки, вы можете использовать:

    all_treatments['month'] = all_treatments.INDATUMA % 10000 // 100

  3. Наконец, вместо того, чтобы применять ваши лямбда-функции к каждому файлу после его чтения, попробуйте применить их к all_treatments DataFrame.

ps Вы также можете попробовать .sum() в своем заявлении groupby вместо .aggregate(np.count_nonzero)

  • Pandas: как получить уникальное количество значений в ячейках, когда ячейки содержат списки?
  • панды описывают - дополнительные параметры
  • Замените целую строку, если она содержит подстроку в пандах
  • Ошибка Matplotlib / Pandas с использованием гистограммы
  • Вставьте отсутствующие рабочие дни в кадре данных pandas и заполните их NaN
  • Написание и изменение существующей книги с использованием Python
  • Python устанавливает панды
  • «Ошибка шины: 10» при попытке установить имя столбца pandas
  • Python - лучший язык программирования в мире.