调用lace包cliff函数遇TypeError:map对象不可下标问题
问题分析
错误TypeError: 'map' object is not subscriptable的核心原因是Python3中map()返回的是迭代器而非列表:迭代器不支持下标访问(如[x]语法),且只能被遍历一次。你之前尝试转list但未覆盖所有关键位置,导致错误仍存在。结合代码,主要问题点包括:
- 迭代器被消耗后无法复用:比如
cliff函数中alldata是map迭代器,传入cliff_core后,zip(*data)会遍历消耗掉data,后续代码无法再获取数据。 - 迭代器不支持下标操作:比如
zip(*data)[-1]中,zip(*data)返回的是zip迭代器,无法用[-1]取最后一列;map对象本身也不能下标访问。 random.shuffle不支持迭代器:filter()返回的是迭代器,而random.shuffle()要求传入可变序列(如列表)。
修复后的完整代码
1. power函数(同步修正原代码缩进问题)
import copy def power(L, C, Erange): assert len(L) == len(C), "The L and C must be corresponded to each other" E = copy.deepcopy(Erange) E[0] -= 1 power_table = dict() for c in set(C): # 遍历每个类别 first = [index for index, eachc in enumerate(C) if eachc == c] rest = [index for index, eachc in enumerate(C) if eachc != c] p_first = len(first) / len(L) p_rest = len(rest) / len(L) powerc = [] for u, v in zip(E[0:-1], E[1:]): # 检查区间(u,v] like_first = sum([1 for i in first if u < L[i] <= v]) / len(first) * p_first like_rest = sum([1 for i in rest if u < L[i] <= v]) / len(rest) * p_rest try: powerc.append((like_first ** 2 / (like_first + like_rest))) except ZeroDivisionError: powerc.append(0) power_table[c] = powerc power_list = [] for l, c in zip(L, C): for e_cursor in range(len(E)): if E[e_cursor] >= l: break power_list.append(round(power_table[c][e_cursor - 1], 2)) return power_list
2. cliff_core函数
import logging import random def cliff_core(data, percentage, obj_as_binary, handled_obj=False): # 先将data转成列表,避免迭代器被一次性消耗 data = list(data) if len(data) < 50: logging.debug("no enough data to cliff. return the whole dataset") return list(range(len(data))) # 转置数据并取最后一列,先转成列表再操作(避免zip迭代器无法下标访问) data_transposed = list(zip(*data)) classes = [toolkit.str2num(item) for item in data_transposed[-1]] if not handled_obj: if obj_as_binary: classes = [1 if i > 0 else 0 for i in classes] else: classes = toolkit.apply_bin_range(classes) data_power = [] for col in data_transposed: # 将列数据转成列表,避免迭代器问题 col = [toolkit.str2num(item) for item in col] E = toolkit.binrange(col) data_power.append(power(col, classes, E)) # 转置data_power并转成列表 data_power = list(map(list, zip(*data_power))) row_sum = [sum(row) for row in data_power] index = list(range(len(data))) zips = list(zip(data, classes, row_sum, index)) output = [] for cls in set(classes): # 将filter结果转成列表,支持shuffle操作 matched = list(filter(lambda z: z[1] == cls, zips)) random.shuffle(matched) matched = sorted(matched, key=lambda z: z[2], reverse=True) if len(matched) < 5: output.extend([m[3] for m in matched]) # 保留所有数据 continue for i in range(int(len(matched) * percentage)): output.append(matched[i][3]) return sorted(output)
3. cliff函数
def cliff(attribute_names, data_matrix, independent_attrs, objective_attr, objective_as_binary=False, cliff_percentage=0.4): ori_attrs, alldata = attribute_names, data_matrix # 转成列表,避免迭代器问题 alldata_t = list(map(list, zip(*alldata))) valued_data_t = [] for attr, col in zip(ori_attrs, alldata_t): if attr in independent_attrs: valued_data_t.append(col) # 添加目标属性列 valued_data_t.append(alldata_t[attribute_names.index(objective_attr)]) # 转成列表 alldata = list(map(list, zip(*valued_data_t))) # 将所有元素转成数值,嵌套转成列表 alldata = [list(map(toolkit.str2num, row)) for row in alldata] after_cliff = cliff_core(alldata, cliff_percentage, objective_as_binary) res = [data_matrix[i] for i in after_cliff] return res
关键修复点说明
- 所有
map()结果显式转成列表:比如alldata = list(map(...)),确保数据是可重复访问、支持下标的列表类型。 - 转置数据时先转成列表:
data_transposed = list(zip(*data)),避免zip迭代器无法下标访问的问题,同时保留转置后的所有列数据。 filter()结果转成列表:matched = list(filter(...)),让random.shuffle()可以正常修改序列。- 嵌套迭代器转列表:
alldata = [list(map(...)) for row in alldata],将每行的map迭代器转成列表,确保后续可以正常访问每行元素。
内容的提问来源于stack exchange,提问作者NDaq
相关产品推荐
相关产品推荐

