2017-09-05 65 views
4

我有兩個數據框,df和df2,它們是通訊組。 現在基於第一個數據框df,我想在一行中得到3個最小值,並返回對應列的名稱(在本例中爲「X」或「Y」或「Z」或「T」)。所以我可以得到新的數據幀df3。獲取每行三個最小值並返回相應的列名稱

df = pd.DataFrame({ 
     'X': [21, 2, 43, 44, 56, 67, 7, 38, 29, 130], 
     'Y': [101, 220, 330, 140, 250, 10, 207, 320, 420, 50], 
     'Z': [20, 128, 136, 144, 312, 10, 82, 63, 42, 12], 
     'T': [2, 32, 4, 424, 256, 167, 27, 38, 229, 30] 
    }, index=list('ABCDEFGHIJ')) 

df2 = pd.DataFrame({ 
     'X': [0.5, 0.12,0.43, 0.424, 0.65,0.867,0.17,0.938,0.229,0.113], 
     'Y': [0.1,2.201,0.33,0.140,0.525,0.31,0.20,0.32,0.420,0.650], 
     'Z': [0.20,0.128,0.136,0.2144,0.5312,0.61,0.82,0.363,0.542,0.512], 
     'T':[0.52, 0.232,0.34, 0.6424, 0.6256,0.3167,0.527,0.38,0.4229,0.73] 
    },index=list('ABCDEFGHIJ')) 

除此之外,我想另一個數據幀DF4這是記者從DF3 DF2中,這意味着在DF行[「A」(2,20,21)是3最小值,所以在DF4行['A'],我想從df2獲得(0.52,0.2,0.5)。

謝謝。

+0

什麼是DF和DF2以及如何之間的關係是它涉及創建DF3? –

+0

df和df2不相關。在創建df3時,我們應該只使用df。 – Hong

+0

Numpy解決方案約。接受答案的速度提高10倍,在我的答案中查看時間。 – jezrael

回答

2

您可以使用,如果這兩個DataFrames具有相同的順序argsort相同的列名的索引:

arr = df.values.argsort(1)[:,:3] 
print (arr) 
[[0 3 1] 
[1 0 3] 
[0 1 3] 
[1 2 3] 
[1 2 0] 
[2 3 1] 
[1 0 3] 
[0 1 3] 
[1 3 0] 
[3 0 2]] 

#get values by indices in arr 
b = df2.values[np.arange(len(arr))[:,None], arr] 
print (b) 
[[ 0.52 0.2  0.5 ] 
[ 0.12 0.232 0.128 ] 
[ 0.34 0.43 0.136 ] 
[ 0.424 0.14 0.2144] 
[ 0.65 0.525 0.6256] 
[ 0.31 0.61 0.867 ] 
[ 0.17 0.527 0.82 ] 
[ 0.38 0.938 0.363 ] 
[ 0.229 0.542 0.4229] 
[ 0.512 0.73 0.65 ]] 

最後使用DataFrame構造函數:

df3 = pd.DataFrame(df.columns[arr]) 
df3.columns = ['Col{}'.format(x+1) for x in df3.columns] 
print (df3) 
    Col1 Col2 Col3 
0 T Z X 
1 X T Z 
2 T X Z 
3 X Y Z 
4 X Y T 
5 Y Z X 
6 X T Z 
7 T X Z 
8 X Z T 
9 Z T Y 

df4 = pd.DataFrame(b) 
df4.columns = ['Col{}'.format(x+1) for x in df4.columns] 
print (df4) 
    Col1 Col2 Col3 
0 0.520 0.200 0.5000 
1 0.120 0.232 0.1280 
2 0.340 0.430 0.1360 
3 0.424 0.140 0.2144 
4 0.650 0.525 0.6256 
5 0.310 0.610 0.8670 
6 0.170 0.527 0.8200 
7 0.380 0.938 0.3630 
8 0.229 0.542 0.4229 
9 0.512 0.730 0.6500 

答案是相似的,所以我創建了計時

np.random.seed(14) 
N = 1000000 
df1 = pd.DataFrame(np.random.randint(100, size=(N, 4)), columns=['X','Y','Z','T']) 
#print (df1) 

df1 = pd.DataFrame(np.random.rand(N, 4), columns=['X','Y','Z','T']) 
#print (df1) 


def jez(): 
    arr = df.values.argsort(1)[:,:3] 
    b = df2.values[np.arange(len(arr))[:,None], arr] 
    df3 = pd.DataFrame(df.columns[arr]) 
    df3.columns = ['Col{}'.format(x+1) for x in df3.columns] 
    df4 = pd.DataFrame(b) 
    df4.columns = ['Col{}'.format(x+1) for x in df4.columns] 


def pir(): 
    v = df.values 
    a = v.argpartition(3, 1)[:, :3] 
    c = df.columns.values[a] 
    pd.DataFrame(c, df.index) 
    d = df2.values[np.arange(len(df))[:, None], a] 
    pd.DataFrame(d, df.index, [1, 2, 3]).add_prefix('Col') 

def cᴏʟᴅsᴘᴇᴇᴅ(): 
    #another solution is wrong 
    df3 = df.apply(lambda x: df.columns[np.argsort(x)], 1).iloc[:, :3] 
    pd.DataFrame({'Col{}'.format(i + 1) : df2.lookup(df3.index, df3.iloc[:, i]) for i in range(df3.shape[1])}, index=df.index) 


print (jez()) 
print (pir()) 
print (cᴏʟᴅsᴘᴇᴇᴅ()) 

In [176]: %timeit (jez()) 
1000 loops, best of 3: 412 µs per loop 

In [177]: %timeit (pir()) 
1000 loops, best of 3: 425 µs per loop 

In [178]: %timeit (cᴏʟᴅsᴘᴇᴇᴅ()) 
100 loops, best of 3: 3.99 ms per loop 
+0

第二種解決方案是正確的。第一個解決方案不包含標題。它們是相同的。 –

+1

我嘗試了df4的ger錯誤,我想只有一些錯字,你能檢查它嗎? – jezrael

+0

是的。該指數已關閉。我的第二個解決方案是1.5ms。 –

2

您可以使用np.argsort來檢索每一行中最小項目的列名稱。

df3 = df.apply(lambda x: df.columns[np.argsort(x)], 1).iloc[:, :3] 
print(df3) 

A T Z X 
B X T Z 
C T X Z 
D X Y Z 
E X Y T 
F Y Z X 
G X T Z 
H T X Z 
I X Z T 
J Z T Y 

,這是讓df3的改進涉及索引df.columns直接(通過jezrael's answer啓發):

​​

使用df3,索引df2使用df.lookup

df4 = pd.DataFrame({'Col{}'.format(i + 1) : df2.lookup(df3.index, df3.iloc[:, i])\ 
             for i in range(df3.shape[1])}, index=df.index) 
print(df4) 

    Col1 Col2 Col3 
A 0.520 0.200 0.5000 
B 0.120 0.232 0.1280 
C 0.340 0.430 0.1360 
D 0.424 0.140 0.2144 
E 0.650 0.525 0.6256 
F 0.310 0.610 0.8670 
G 0.170 0.527 0.8200 
H 0.380 0.938 0.3630 
I 0.229 0.542 0.4229 
J 0.512 0.730 0.6500 

2

我會用numpy.argpartition,因爲它只是看起來每一行劃分成底部k和休息。由於不需要完全排序,其時間複雜度爲O(n)而不是O(nlogn)。我們可以在此基礎上定義df3

df3 = pd.DataFrame(c, df.index) 

df3 

    0 1 2 
A T Z X 
B X T Z 
C T X Z 
D Y X Z 
E Y X T 
F Y Z X 
G X T Z 
H X T Z 
I X Z T 
J Z T Y 

你可以用它來創造df4

d = df2.values[np.arange(len(df))[:, None], a] 
df4 = pd.DataFrame(d, df.index, [1, 2, 3]).add_prefix('Col') 
df4 

    Col1 Col2 Col3 
A 0.520 0.200 0.5000 
B 0.120 0.232 0.1280 
C 0.340 0.430 0.1360 
D 0.140 0.424 0.2144 
E 0.525 0.650 0.6256 
F 0.310 0.610 0.8670 
G 0.170 0.527 0.8200 
H 0.938 0.380 0.3630 
I 0.229 0.542 0.4229 
J 0.512 0.730 0.6500 
相關問題