我正在参加一个机器学习竞赛,目标是根据客户去超市的行程信息,预测客户行程的类型或动机。我有一个如下格式的CSV文件:
TripType,VisitNumber,Weekday,Upc,ScanCount,DepartmentDescription,FinelineNumber999,5,Friday,68113152929,-1,FINANCIAL SERVICES,100030,7,Friday,60538815980,1,SHOES,893130,7,Friday,7410811099,1,PERSONAL CARE,450426,8,Friday,2238403510,2,PAINT AND ACCESSORIES,356526,8,Friday,2006613744,2,PAINT AND ACCESSORIES,1017
我的第一步是将这些数据转换成特征向量。为此,我将每个分类变量转换成虚拟变量,然后每个向量将是一个独特的样本。创建向量的问题在于样本不是按行分隔的;你会在不同的行上找到关于样本的数据。例如,上面有5行但只有3个样本(5、7和8)。以下是上述样本的特征向量:
'Friday', 68113152929, 60538815980, 7410811099, 2238403510, 2006613744, 'FINANCIAL SERVICES', 'SHOES', 'PERSONAL CARE', 'PAINT AND ACCESSORIES', 1000, 8931, 4504, 3565, 1017, 'Returned' [ 1. 0. 0. 0. 0. 0. 1. 0. 0. 0. 1. 0. 0. 0. 0. 1.] [ 1. 0. 1. 1. 0. 0. 0. 1. 1. 0. 0. 1. 1. 0. 0. 0.] [ 1. 0. 0. 0. 2. 2. 0. 0. 0. 1. 0. 0. 0. 1. 1. 0.]
请注意,我在最后添加了“Returned”特征(当任何Upc或购买的物品的扫描计数为负时,此特征为1)。还会有一个包含相应标签的“目标”向量:
[999, 30, 26]
我的问题是如何高效地生成这些向量。我在程序的这一部分上花的时间相对较少,仅在总数据的一小部分(100 – 1000行)上测试了我的代码(总数据约70万行)。当我完成程序的其余部分(学习和预测部分)并返回到整个数据时,“向量化”部分似乎花费了太长时间。你有什么建议来改进这个过程(从CSV文件中获取特征向量)以获得更好的性能吗?
这是我目前使用的代码。如果你想知道我现在在做什么,请查看一下。直接跳到“按行迭代”部分以查看向量化部分:
import pandas as pd#通过在开头添加零来重塑较小的向量。添加向量,但如果两个向量中都有非零值,则添加0def vector_add(P, Q): a = [] for x,y in izip_longest(reversed(P), reversed(Q), fillvalue=0): if x == 0 or y == 0: a.append(x+y) else: a.append(1) return a[::-1]csv_file = open('exp-train', 'rb')df = pd.read_csv(csv_file)# 获取特征visitnums = df.drop_duplicates(subset='VisitNumber')['VisitNumber']days = df.drop_duplicates(subset='Weekday')['Weekday']upcs = df.drop_duplicates(subset='Upc')['Upc']departments = df.drop_duplicates(subset='DepartmentDescription')['DepartmentDescription']finenums = df.drop_duplicates(subset='FinelineNumber')['FinelineNumber']# 包含所有特征向量的列表lines = []# 放入列表并将列表放入大列表中top_line = []top_line.append('VisitType')for day in days: top_line.append(day)for upc in upcs: top_line.append(upc)for department in departments: top_line.append(department)for finenum in finenums: top_line.append(finenum)top_line.append('Returned')lines.append(top_line)#按行迭代counter = 0#处理重复样本的back变量back = 'no'line = []returned = 0for i, row in enumerate(df.itertuples()):#处理重复样本的line2line2 = []if not back == row[2]: if not back == 'no': line.append(returned) returned = 0 lines.append(line) line = [] line.append(row[1]) for day in days: if day == row[3]: line.append(1) else: line.append(0) for upc in upcs: if upc == row[4]: if int(row[5]) < 0: returned = 1 line.append(0) else: line.append(int(row[5])) else: line.append(0) for department in departments: if department == row[6]: line.append(1) else: line.append(0) for finenum in finenums: if finenum == row[7]: line.append(1) else: line.append(0)else: for upc in upcs: if upc == row[4]: if int(row[5]) < 0: returned = 1 line2.append(0) else: line2.append(int(row[5])) else: line2.append(0) for department in departments: if department == row[6]: line2.append(1) else: line2.append(0) for finenum in finenums: if finenum == row[7]: line2.append(1) else: line2.append(0) #通过将line和line2添加到line中处理多个样本 line = vector_add(line, line2)back = row[2]if i == (len(df.index) - 1): line.append(returned) returned = 0 lines.append(line)a = time.time()
请告诉我是否有更好的方法来处理这个问题。
回答:
纯Python代码可能非常慢——这就是为什么numpy等使用C、Fortran和Cython编写的原因。
例如,纯Python中的整数使用12字节而不是8字节存储。通过append
构建list()
整数预计会很慢且开销大。
为了加速,尝试
- 分配一个所需的整数零的numpy向量
- 不追加0和1,只设置1,忽略0
还可以使用Python分析器来识别你的热点在哪里。