1. 程式人生 > >python numpy在保持行的整體性的情況下按列排序

python numpy在保持行的整體性的情況下按列排序

某公司的資料日常處理。看著規整的資料我就想到了numpy。

這是資料:

>>>> a
array([[ 2,  7,  1,  2],
       [35, 9, 1, 2],
       [22,  12,  4,  2]])
>>> 

按照第一列排序,想要變成這樣的效果:
>>> a
array([[ 2,  7,  1,  2],
       [22, 12, 4, 2],
       [35,  9,  1,  2]])
>>> 

行的整體性並沒有被破壞。


開寫:
# -*- coding: cp936 -*-

import numpy as np
import pprint 
a = np.array(
                [[  2,  7,  1, 2],
                [ 35,  9,  1, 2],
                [ 22, 12,  4, 2]]
             )

a1 = a[:,::-1].T
a2 = np.lexsort(a1)
a3 = a[a2]

pprint.pprint(a3)

好吧,就3行,開始寫註釋吧,不然自己都會忘了(不可能,我這麼帥,怎麼可能忘記)
a1 = a[:,::-1].T
註釋:
#先逆序再轉置
#逆序結果:
#[2,1,7,2]
#[2,1,9,35]
#[2,4,12,22]
#轉置結果:
#[2,2,2]
#[1,1,4]
#[7,9,12]
#[2,35,22]


a2 = np.lexsort(a1)
註釋:
#np.lexsort(),以列為整體性進行排序,重點是:從最後一行開始比較大小,正因為從最後一行開始排序,前面才用逆序
#排序結果:
#[0 2 1]
#0表示,排序後的第1列在a1的第0列,[2,1,7,2]
#2表示,排序後的第2列在a1的第2列,[2,4,12,22]
#1表示,排序後的第3列在a1的第1列,[2,1,9,35]


a3 = a[a2]
註釋:
#拿著新的序列號[0 2 1],調整下a就是我們要的結果了



好了,思考下,如果按第二列排序怎麼辦?

Ps:之前的資料本來排好序了,更換下資料。

開寫:

# -*- coding: cp936 -*-

import numpy as np
from numpy import * 
import pprint 
a = np.array(
                [[  2,  77,  1, 2],
                [ 35,  9,  1, 2],
                [ 22, 12,  4, 2]]
             )
print '排序前:'
pprint.pprint(a)

a1 = a.T
a2 = a1[array([0,3,2,1])]  #2列換到最後列(因為轉置,此時應該說2行換最後行)
a3 = np.lexsort(a2)
a4 = a[a3]

print '排序後:'
pprint.pprint(a4)
結果:
>>> 
排序前:
array([[ 2, 77,  1,  2],
       [35,  9,  1,  2],
       [22, 12,  4,  2]])
排序後:
array([[35,  9,  1,  2],
       [22, 12,  4,  2],
       [ 2, 77,  1,  2]])
>>> 

其實就是把第2列換到最後一列,然後重複之前的操作。

好吧,思考下,按照任意列排序,怎麼搞?

輸入引數:col_index(0,1,2,3...)表示按照第col_index列排序。

分析:因為轉置的原因,題目要求等價於按照轉置後的第col_index行排序。

這個還真有點意思,因為coding的時候,要把第col_index行和最後一行互換,不知道怎麼寫這個:

if col_index = 0: a2 = a1[array([3,1,2,col_index])]
if col_index = 1: a2 = a1[array([0,3,2,col_index])]
if col_index = 2: a2 = a1[array([0,1,3,col_index])]
if col_index = 3: a2 = a1[array([0,1,2,col_index])]

我可不想用100個if來表示100列。

動態生成?不可能,我肯定避開不了做判斷的時候。

算了,既然資料保證了每一行格式都是規整的,直接兩行交換吧。numpy做兩行運算還是挺快的。

交換a,b :a = a + b, b = a - b, a = a- b。

# -*- coding: cp936 -*-

import numpy as np
from numpy import * 
import pprint 
a = np.array(
                [[  2,  77,  1, 2],
                [ 35,  9,  1, 2],
                [ 22, 12,  4, 2]]
             )
print '排序前:'
pprint.pprint(a)


def sort_by_col(a,col_index):
    a1 = a.T

    col_max = a.shape[-1]-1

    if col_index < col_max:
        #兩行互換
        a1[col_index] = a1[col_index] + a1[col_max]
        a1[col_max] = a1[col_index] - a1[col_max]
        a1[col_index] = a1[col_index] - a1[col_max]
        
        a2 = np.lexsort(a1)

        #因為a1的行交換影響了a(雖然id不同,但是是同一片記憶體),得到序列結果後再換回來,保持a的純潔
        a1[col_index] = a1[col_index] + a1[col_max]
        a1[col_max] = a1[col_index] - a1[col_max]
        a1[col_index] = a1[col_index] - a1[col_max]
    else:
        a2 = np.lexsort(a1)
    
    return a[a2]



for i in range(4):
    col_index = i
    a = sort_by_col(a,col_index)
    print '當col_index = %d ,排序後:' % col_index
    pprint.pprint(a)
結果:
>>> 
排序前:
array([[ 2, 77,  1,  2],
       [35,  9,  1,  2],
       [22, 12,  4,  2]])
當col_index = 0 ,排序後:
array([[ 2, 77,  1,  2],
       [22, 12,  4,  2],
       [35,  9,  1,  2]])
當col_index = 1 ,排序後:
array([[35,  9,  1,  2],
       [22, 12,  4,  2],
       [ 2, 77,  1,  2]])
當col_index = 2 ,排序後:
array([[35,  9,  1,  2],
       [ 2, 77,  1,  2],
       [22, 12,  4,  2]])
當col_index = 3 ,排序後:
array([[35,  9,  1,  2],
       [ 2, 77,  1,  2],
       [22, 12,  4,  2]])
>>>