Pandas auto convert list to tuple error

Pandas 自动转格式(list to tuple)问题

问题描述

一向稳定的线上,突然报出一个错误:
AttributeError: 'tuple' object has no attribute 'remove'
意思是元组(tuple)没有remove方法,但是代码逻辑设计的是针对列表(list)使用的,且安全生产了很久很久……

结果

经过不懈努力,目前暂时结论:pandas在处理某种特殊情形时,默认会自动将列表转为元组,如下:
df新增一列,如果该列的元素是一个二维数组(外层元组),那么问题来了:

  • 如果每一个元素列表长度均一致,不论列表内元素个数及格式,均转为元组,如:b,c,d;
  • 如果元素列表的长度不一致,保持原格式,即,依旧是列表,如:p,v;
  • 一维数组格式不存在此类问题,如:z;
  • 二维数组(外层列表)格式也不存在此类问题,如:q。
import pandas as pd # version 0.23.4 ;python 2/3
a = pd.DataFrame()
a['p'] = ([],[1],[1],[1],[1])
a['v'] = ([1,2],[1],[1],[1],[1])
a['b'] = (['1'],[1],[1],['1'],[1])
a['c'] = ([],[],[],[],[])
a['d'] = ([1,2],[1,2],[1,2],[1,2],[1,2])
a['q'] = [[1,2],[1,2],[1,2],[1,2],[1,2]]
a

Pandas auto convert list to tuple error

追问

就问你,为什么会出现这种外层元组内层列表这种奇葩的二维数组格式的数据?

data = {……} # 手机号的补充信息,键是手机号(str), 值是与手机号相关的一列信息(list)
def inr_columns(x):
	return data.get(x)[0], data.get(x)[1], data.get(x)[2], data.get(x)[3], data.get(x)[4]
df = pd.DataFrame({}) # 一个基于手机号的df
# 现在要从data里,给df补充几列信息,所以:
df['user'], df['loc'], df['innetMons'], df['label'] = zip(*df.call_tel.map(inr_columns))

问题就出现在最后的zip身上,带星号(*)的zip方法生成的是[(),(),(),...]这种结构,而label的值是列表(list),所以,在添加label这列的时候,就出现了这种外元组内列表的情况,解决方案,map一下:

map(list, zip(*df.call_tel.map(inr_columns)))

科普:

zip

用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表,即二维数组
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同
利用* 号操作符,可以将二维数组解压为列表

a = [1,2,3]
b = [4,5,6]
c = [4,5,6,7,8]
print(list(zip(a,b)))         # 打包为元组的列表
print(list(zip(a,c)))         # 元素个数与最短的列表一致
print(list(zip(*zip(a,b))))   # 与 zip 相反,*zip 可理解为解压,返回二维矩阵式

Pandas auto convert list to tuple error