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

Python 使用Pandas中的字典从两列创建新列,python,pandas,dictionary,pandas-apply,Python,Pandas,Dictionary,Pandas Apply,我想基于组和阈值创建一个列,用于为分组列的每个组从另一列断开 数据帧如下所示: 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

我想基于组和阈值创建一个列,用于为分组列的每个组从另一列断开

数据帧如下所示:

     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}
因此,我的目标是根据以下条件创建一个新列,称为“chk”:

如果“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 ->

         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

这是可行的,但效率极低,需要一种更好的方法来实现。

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

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

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

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
这应该更快:

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
虽然在这样一个小的例子中,它不是决定性的。

这应该更快:

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

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

您想要的是将一个函数应用于所有df。你有没有检查过你想要的是把一个函数应用到你所有的df上。您是否已检查此项不起作用,因为它无法确保idCol与字典键以及相应的。我需要满足这两个条件。您的代码确保只满足myvalue标准。此代码根据
idCol
从词典中选取值。你不必遍历整本字典就能做到这一点。字典对该键进行散列,并返回与该键关联的值(如果存在)。如果不存在键,则返回值
None
。因此,检查
idCol
是否匹配是多余的。这只是为了在不使用apply的情况下提高性能。尽管,apply可能是您想要的。这不起作用,因为它无法确保idCol与字典键以及相应的。我需要满足这两个条件。您的代码确保只满足myvalue标准。此代码根据
idCol
从词典中选取值。你不必遍历整本字典就能做到这一点。字典对该键进行散列,并返回与该键关联的值(如果存在)。如果不存在键,则返回值
None
。因此,检查
idCol
是否匹配是多余的。这只是为了在不使用apply的情况下提高性能。虽然,申请可能是你想要的。谢谢。我觉得这样好多了。如何修改函数并将dict作为参数应用,例如:def func(identif,value,md):??在这种情况下,apply函数将如何更改。我们只需将其作为参数传递,如so
df['chk']=df.apply(lambda行:func(行['identif',行['myvalue',md],轴=1)
Perfect!!工作起来很有魅力!谢谢,谢谢。我觉得这样好多了。如何修改函数并将dict作为参数应用,例如:def func(identif,value,md):??在这种情况下,apply函数将如何更改。我们只需将其作为参数传递,如so
df['chk']=df.apply(lambda行:func(行['identif',行['myvalue',md],轴=1)
Perfect!!工作起来很有魅力!谢谢