Python Pandas—在列中作为字典加载转储的json时提高内存使用率 背景

Python Pandas—在列中作为字典加载转储的json时提高内存使用率 背景,python,json,pandas,dictionary,Python,Json,Pandas,Dictionary,我使用pandas从DB(redshift)加载一个大数据集(最多几百万行),DB中的一些列最初是以字符串形式保存的json。加载数据后,我使用json.loads将包含转储json对象的单元格转换为字典。这些对象每个单元大约有2.5MB 问题 在处理大数据帧时,此过程可能需要超过10GB的内存才能完成,甚至会在某些机器上崩溃。 执行时间也很慢,但这对我来说是个小问题。 只有当单元格包含大型json对象时,问题才会显现出来 所有操作都在内存中完成,我宁愿避免使用HDFS或其他磁盘解决方案,因为数

我使用pandas从DB(redshift)加载一个大数据集(最多几百万行),DB中的一些列最初是以字符串形式保存的json。加载数据后,我使用json.loads将包含转储json对象的单元格转换为字典。这些对象每个单元大约有2.5MB

问题 在处理大数据帧时,此过程可能需要超过10GB的内存才能完成,甚至会在某些机器上崩溃。 执行时间也很慢,但这对我来说是个小问题。 只有当单元格包含大型json对象时,问题才会显现出来

所有操作都在内存中完成,我宁愿避免使用HDFS或其他磁盘解决方案,因为数据帧本身在内存中更易于管理

解决方案尝试失败 使用另一个模块解析字典- 我尝试过使用ujson、simplejson和ast.literal_eval代替json模块,但在性能上没有明显的差异

使用apply和使用map-两者都尝试过,但似乎都没有改善内存使用问题

代码 数据帧作为self.df保存在类中,这是处理转换的代码:

def turnAllJsonColumnsToDict(self):
    """
    Scan the df and turn column to json if it's a string in json format
    """
    print 'Checking columns for needed type conversions'
    for col in self.df.columns:
        if self.check_if_json(self.df[col].iloc[0], col):
            self.loadColumnAsJson(col)

@staticmethod
def check_if_json(col, col_name, should_print=True):
    if isinstance(col, basestring):
        try:
            if col[0] in ('{', '[') and col[-1] in ('}', ']'):
                if should_print:
                    print 'Converting', col_name
                return True
        except IndexError as e:
            if should_print:
                print 'Failed to check ', col_name

@timeIt
def loadColumnAsJson(self, column):
    self.json_load_fail_counter = 0
    self.df[column] = map(self.loadJson, self.df[column])
    print '{failed} cells failed to be parsed to json in {column} (out of {rows})'.format(
        failed=self.json_load_fail_counter, column=column,
        rows=len(self.df))

def loadJson(self, value):
    if not value:
        return value

    # the json dump is not in a python structure
    null, true, false = None, True, False
    value = self.fix_dumped_json(value)
    try:
        if type(value) == dict:
            return value
        else:
            return json.loads(value) if value else {}
    except Exception as e:
        self.json_load_fail_counter += 1
    return {}

@staticmethod
def fix_dumped_json(value):
    value = value.replace('"None"', 'null')
    counter = 0
    for i in value:
        counter += 1 if i == '{' else -1 if i == '}' else 0
    if counter > 0:
        for c in range(counter):
            value += '}'
    return value