【问题标题】:efficient way to populate pandas dataframe based on conditions from another dataframe根据来自另一个数据帧的条件填充熊猫数据帧的有效方法
【发布时间】:2018-07-15 14:32:27
【问题描述】:

数据

我有一个数据框,其中包含给定 ID 的排名分数:

>>> ranks
  ID  rank
0  A     6
1  B     9
2  C     6
3  D     1
4  E     1
5  F     2

我想把它变成一个方阵,每个 ID 既作为索引又作为列,基于几个条件:如果索引上的 ID 排名高于 ID 在索引中的排名列,设置为1,如果小于,设置为0,如果相等,设置为0.5,如果索引与列相同,设置为np.nan。通过查看我想要的矩阵可以更好地描述这一点:

期望的结果

>>> mtrx
     A    B    C    D    E    F
A  NaN  1.0  0.5  0.0  0.0  0.0
B  0.0  NaN  0.0  0.0  0.0  0.0
C  0.5  1.0  NaN  0.0  0.0  0.0
D  1.0  1.0  1.0  NaN  0.5  1.0
E  1.0  1.0  1.0  0.5  NaN  1.0
F  1.0  1.0  1.0  0.0  0.0  NaN

我所做的(有效,但速度很慢)

以下循环有效,但对于较大的数据帧,它很慢。如果有人可以为我指明一个更好的、更 Pythonic/pandorable 的方式来实现这一点,我希望得到一些帮助:

# Make an empty matrix as a dataframe
mtrx = pd.DataFrame(np.zeros((len(IDs), len(IDs))), index=IDs, columns = IDs)

# Populate it via for loop
for i in IDs:
    for j in IDs:
        i_rank = ranks.loc[ranks['ID'] == i].iloc[0]['rank']
        j_rank = ranks.loc[ranks['ID'] == j].iloc[0]['rank']
        if i == j:
            mtrx.loc[i, j] = np.nan
        elif i_rank < j_rank:
            mtrx.loc[i, j] = 1.
        elif i_rank == j_rank:
            mtrx.loc[i, j] = 0.5

重现此玩具示例的代码

import pandas as pd
import numpy as np
np.random.seed(1)
IDs = list('ABCDEF')
ranks = pd.DataFrame({'ID':IDs, 'rank':np.random.randint(1,10,len(IDs))})

【问题讨论】:

    标签: python pandas matrix


    【解决方案1】:

    numpy接近

    s=ranks['rank'].values
    s1=(s>s[:,None]).astype(int).astype(float)
    s1[s==s[:,None]]=0.5
    s1[[np.arange(len(s))]*2] = np.nan
    pd.DataFrame(s1,index=ranks.ID,columns=ranks.ID)
    
    
    Out[843]: 
    ID    A    B    C    D    E    F
    ID                              
    A   NaN  1.0  0.5  0.0  0.0  0.0
    B   0.0  NaN  0.0  0.0  0.0  0.0
    C   0.5  1.0  NaN  0.0  0.0  0.0
    D   1.0  1.0  1.0  NaN  0.5  1.0
    E   1.0  1.0  1.0  0.5  NaN  1.0
    F   1.0  1.0  1.0  0.0  0.0  NaN
    

    熊猫接近

    s=ranks.assign(key=1).merge(ranks.assign(key=1),on='key')
    s['New']=(s['rank_x']<s['rank_y']).astype(int)
    s.loc[s['rank_x']==s['rank_y'],'New']=0.5
    s.loc[s['ID_x']==s['ID_y'],'New']=np.nan
    
    s.set_index(['ID_x','ID_y']).New.unstack()
    Out[854]: 
    ID_y    A    B    C    D    E    F
    ID_x                              
    A     NaN  1.0  0.5  0.0  0.0  0.0
    B     0.0  NaN  0.0  0.0  0.0  0.0
    C     0.5  1.0  NaN  0.0  0.0  0.0
    D     1.0  1.0  1.0  NaN  0.5  1.0
    E     1.0  1.0  1.0  0.5  NaN  1.0
    F     1.0  1.0  1.0  0.0  0.0  NaN
    

    【讨论】:

    • 太棒了!那要快得多。我会稍等片刻,看看是否有任何 pandas 解决方案(只是出于兴趣),否则我肯定会接受。谢谢!
    • @sacul 是的,应该是 (s['rank_x']
    猜你喜欢
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 2018-12-25
    • 1970-01-01
    • 2017-11-10
    • 2013-06-14
    相关资源
    最近更新 更多