我正在尝试为SVM分类器创建堆叠的特征向量。我所有的数据都存储在一个大型矩阵中。手头的问题是一个多类分类问题,因此我需要使用多索引进行分组。
以下是我试图实现的一个玩具示例。
N = 4col_ids = string.letters[:N]df = pd.DataFrame( np.random.randint(10, size=(16,N)), #np.random.randn(1,N), columns=['col_{}'.format(letter) for letter in col_ids])test_cols = ['test1','test1','test1','test1','test1','test1','test1','test1','test2','test2','test2','test2','test2','test2','test2','test2']test_iter = [1,1,1,1,2,2,2,2,1,1,1,1,2,2,2,2]df.insert(0, 'Activity', test_cols)df.insert(1, 'Iteration', test_iter)
输出结果如下:
Activity Iteration col_A col_B col_C col_D0 test1 1 7 2 9 71 test1 1 9 7 2 72 test1 1 4 4 2 23 test1 1 0 1 0 64 test1 2 3 5 3 35 test1 2 9 5 7 66 test1 2 9 5 8 67 test1 2 9 7 9 18 test2 1 3 2 5 59 test2 1 8 5 9 010 test2 1 8 6 3 911 test2 1 3 9 2 512 test2 2 0 4 4 113 test2 2 7 0 4 614 test2 2 5 4 0 915 test2 2 0 0 5 0
我使用以下groupby来获取适合我应用的分组:
g = df.groupby(["Activity", "Iteration"]) Activity Iteration col_A col_B col_C col_DActivity Iteration test1 1 0 test1 1 7 2 9 7 1 test1 1 9 7 2 7 2 test1 1 4 4 2 2 3 test1 1 0 1 0 6 2 4 test1 2 3 5 3 3 5 test1 2 9 5 7 6 6 test1 2 9 5 8 6 7 test1 2 9 7 9 1test2 1 8 test2 1 3 2 5 5 9 test2 1 8 5 9 0 10 test2 1 8 6 3 9 11 test2 1 3 9 2 5 2 12 test2 2 0 4 4 1 13 test2 2 7 0 4 6 14 test2 2 5 4 0 9 15 test2 2 0 0 5 0
现在我想创建特征向量并将它们存储在一个新的DataFrame中,但我希望以一种方式进行操作,即使用两行数据来创建一个特征向量。也就是说,在测试示例中,test1
活动执行了两次,每次迭代都有相同的标签,因此在这种情况下它有两个标签:1和2。每个标签应该从两行数据中堆叠起来以创建所需的输出。
从test1
中,我希望创建四个行向量,使得完整的输出(理想情况下)看起来像这样:
test1 test1 ... test2 7 4 5 2 4 4 9 2 0 7 2 9 9 0 0 7 1 0 2 0 5 7 6 9
我没有写出全部内容,但我希望我的意图是显而易见的。基本上,两行数据变成一个堆叠的行向量(顶部带有标签),这个向量就是一个特征向量。由于我有多个活动,我需要为每个活动创建多个特征向量来训练SVM。对于这个示例,我理想情况下会得到一个包含八个特征行向量的pd.DataFrame,因此数据框将从(16,4)重塑为(8,8)(忽略col_A到col_B之间的实际数据)。
我知道这解释得不是很好,所以如果你需要更多细节,请告诉我,如果你有心情帮助的话。
谢谢。
回答:
你需要向groupby
传递一个函数,该函数为最终输出准备数据,然后重新标记列,就像这样:
def f(x): values = [v for vals in x.values for v in vals[2:]] return pd.Series(values,name=x.values[0][0])res = df.groupby(["Activity", "Iteration"]).apply(f)res = res.T.rename(columns={(t,i):t for t,i in res.index})print df print res
在我的测试输出中是这样的:(请注意,数据是随机的!)
Activity Iteration col_A col_B col_C col_D0 test1 1 4 6 5 71 test1 1 5 9 5 42 test1 1 1 8 7 93 test1 1 4 8 1 94 test1 2 4 5 5 65 test1 2 6 3 8 66 test1 2 8 1 1 27 test1 2 5 1 8 18 test2 1 6 3 9 99 test2 1 4 9 9 710 test2 1 5 0 1 311 test2 1 5 8 9 512 test2 2 4 8 3 213 test2 2 8 9 9 414 test2 2 6 1 1 815 test2 2 6 4 4 8 test1 test1 test2 test20 4 4 6 41 6 5 3 82 5 5 9 33 7 6 9 24 5 6 4 85 9 3 9 96 5 8 9 97 4 6 7 48 1 8 5 69 8 1 0 110 7 1 1 111 9 2 3 812 4 5 5 613 8 1 8 414 1 8 9 415 9 1 5 8
每个测试的8个元素的2列稍微复杂一些,但你可以用相同的方式做到这一点:
def g(x): values = [v for vals in x.values for v in vals[2:]] return pd.DataFrame({1: values[:N/2*len(x)], 2: values[N/2*len(x):]})res = df.groupby(["Activity", "Iteration"]).apply(g).unstack()r1 = res[1].T.rename(columns={(t,i):t+str(i)+"1" for t,i in res.index})r2 = res[2].T.rename(columns={(t,i):t+str(i)+"2" for t,i in res.index})res = pd.concat([r1,r2],axis=1).sort(axis=1)res = res.rename(columns={t:t[:-2] for t in res.columns})print dfprint res
输出结果如下:
Activity Iteration col_A col_B col_C col_D0 test1 1 0 8 1 71 test1 1 2 0 5 02 test1 1 2 6 6 63 test1 1 5 0 1 44 test1 2 4 5 6 85 test1 2 8 0 1 66 test1 2 6 7 2 47 test1 2 3 2 2 38 test2 1 5 2 1 99 test2 1 8 3 5 910 test2 1 3 7 7 111 test2 1 7 4 5 112 test2 2 9 2 4 013 test2 2 3 1 8 714 test2 2 1 2 7 815 test2 2 4 9 7 0 test1 test1 test1 test1 test2 test2 test2 test20 0 2 4 6 5 3 9 11 8 6 5 7 2 7 2 22 1 6 6 2 1 7 4 73 7 6 8 4 9 1 0 84 2 5 8 3 8 7 3 45 0 0 0 2 3 4 1 96 5 1 1 2 5 5 8 77 0 4 6 3 9 1 7 0
希望这对你有帮助