代码之家  ›  专栏  ›  技术社区  ›  Stan

使用Pandas中的字典从两列创建新列

  •  0
  • Stan  · 技术社区  · 7 年前

    数据帧如下所示:

         df_in -> 
    
           unique_id  myvalue identif
       0      CTA15   19.0     TOP
       1      CTA15   22.0     TOP
       2      CTA15   28.0     TOP
       3      CTA15   18.0     TOP
       4      CTA15   22.4     TOP
       5      AC007    2.0     TOP
       6      AC007    2.3    SDME
       7      AC007    2.0    SDME
       8      AC007    5.0    SDME
       9      AC007    3.0    SDME
       10     AC007   31.4    SDME
       11     AC007    4.4    SDME
       12      CGT6    9.7    BTME
       13      CGT6   44.5    BTME
       14      TVF5    6.7    BTME
       15      TVF5    9.1    BTME
       16      TVF5   10.0    BTME
       17      BGD1    1.0    BTME
       18      BGD1    1.6     NON
       19       GHB   51.0     NON
       20       GHB   54.0     NON
       21       GHB    4.7     NON
    

    因此,我根据“identif”列的每组创建了一个字典,如下所示:

        md = {'TOP': 22, 'SDME': 10, 'BTME': 20, 'NON':20}
    

    如果“identif”列与字典“md”中的键匹配,且该键的值为>=而不是“myvalue”列中的相应值 我将有1,否则为0。

    但是,我正试图找到一种使用map/groupby/apply创建新输出数据帧的好方法。我现在做的是一种非常低效的方法(在百万行的实际数据上花费了相当多的时间)

     def myfilter(df, idCol, valCol, mydict):
    
       for index,row in df.iterrows():
          for key, value in mydict.items(): 
             if row[idCol] == key and row[valCol] >= value:
                 df['chk'] = 1
             elif row[idCol] == key and row[valCol] < value:
                 df['chk'] = 0
    
      return df
    

    通过以下调用获取输出:

         df_out = myfilter(df_in, 'identif', 'myvalue', md)
    

    因此,我的输出将如下所示:

         df_out ->
    
             unique_id  myvalue identif  chk
        0      CTA15     19.0     TOP    0
        1      CTA15     22.0     TOP    1
        2      CTA15     28.0     TOP    1
        3      CTA15     18.0     TOP    0
        4      CTA15     22.4     TOP    1
        5      AC007      2.0     TOP    0
        6      AC007      2.3    SDME    0
        7      AC007      2.0    SDME    0
        8      AC007      5.0    SDME    0
        9      AC007      3.0    SDME    0
        10     AC007     31.4    SDME    1
        11     AC007      4.4    SDME    0
        12      CGT6      9.7    BTME    0
        13      CGT6     44.5    BTME    1
        14      TVF5      6.7    BTME    0
        15      TVF5      9.1    BTME    0
        16      TVF5     10.0    BTME    0
        17      BGD1      1.0    BTME    0
        18      BGD1      1.6     NON    0
        19       GHB     51.0     NON    1
        20       GHB     54.0     NON    1
        21       GHB      4.7     NON    0
    

    这是可行的,但效率极低,希望有更好的方法。

    3 回复  |  直到 7 年前
        1
  •  1
  •   Rachel    7 年前

    首先,对数据帧中的每一行遍历字典中的每个元素,总共遍历数据集四次。您可以将函数更改为遍历它一次。这将加速您原来的功能。尝试以下方法:

    def myfilter(df, idCol, valCol, mydict):
    
        for index,row in df.iterrows():
            value = mydict.get(row[idCol])
            if row[valCol] >= value:
                df['chk'] = 1
            else:
                df['chk'] = 0
    
        return df
    
        2
  •  1
  •   godfryd    7 年前

    这应该更快:

    def func(identif, value):
        if identif in md:
            if value >= md[identif]:
                return 1.0
            else:
                return 0.0
        else:
            return np.NaN
    
    df['chk'] = df.apply(lambda row: func(row['identif'], row['myvalue']), axis=1)
    

    这个小例子的时机:

    CPU times: user 1.64 ms, sys: 73 µs, total: 1.71 ms
    Wall time: 1.66 ms
    

    您的版本定时:

    CPU times: user 8.6 ms, sys: 1.92 ms, total: 10.5 ms
    Wall time: 8.79 ms
    

    虽然在这样一个小例子上,它不是决定性的。