Python 如何根据多个条件按变量组高效地更新数据帧值?

Python 如何根据多个条件按变量组高效地更新数据帧值?,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个数据框,如下所示: 输入_df: name name_group value foo1 a 2 foo2 a 2 foo3 a 2 foo4 a 2 bar1 b bar2 b bar3 b buzz1 c 6 buzz2 c 6 buzz3

我有一个数据框,如下所示:

输入_df:

name  name_group  value
foo1          a       2
foo2          a       2
foo3          a       2
foo4          a       2
bar1          b
bar2          b
bar3          b
buzz1         c       6
buzz2         c       6
buzz3         c       6
buzz4         c       6
buzz5         c       6
其中,每个名称组中的每一行都有相同的“值”,因此在本例中,名称组“a”中的每一个名称都有相同的“值”,名称组“b”中的每一个名称都有相同的“值”,以此类推

我想创建一个新列“new_vals”,它等于最小值(“name_group”、“value”列中的行数)。如果任何“名称组”的“值”列中缺少值,它应该只使用该“名称组”中的行数。对于我的示例dataframe,所需的输出是:

输出_df:

name  name_group  value   new_vals
foo1          a       2          2
foo2          a       2          2
foo3          a       2          2
foo4          a       2          2
bar1          b                  3
bar2          b                  3
bar3          b                  3
buzz1         c       6          5
buzz2         c       6          5
buzz3         c       6          5
buzz4         c       6          5
buzz5         c       6          5
目前,我实现这一点的方法是通过循环“name_group”列中的每个唯一值,找到该name_组中的行数,将其与“value”列中的值进行比较,然后根据两者之间的最小值设置“new_val”列的值。每个“name_group”的结果将连接到另一个数据帧,直到获得最终输出

虽然这种方法可行,但我觉得必须有一种更有效的方法来实现这一点,而不是将子集作为起始数据帧,分别处理每个“name_group”,然后将所有内容组合在一起。是否有人有一种更具pythonic/效率的方法来复制此功能

下面是一些反映我当前流程的代码:

output_df = pd.DataFrame()
for name_group in input_df['name_group'].unique():
    # process the data one name group at a time
    temp_df = input_df.loc[input_df['name_group'] == name_group]

    max_val = temp_df['value'].max()
    name_group_cnt = temp_df.shape[0]

    # if the "value" column is empty, set new_val equal to the number of
    # rows in that name_group
    if max_val == '':
        new_val = name_group_cnt
    else:
        new_val = min(max_val, name_group_cnt)

    temp_df['new_val'] = new_val
    output_df = pd.concat([output_df, temp_df])

一种解决方案是创建一个临时的
计数
,然后比较值

vs = df.groupby("new_group").size().to_dict()
# vs =  {'a': 4, 'c': 5, 'b': 3}

df["count"] = df["new_group"].apply(lambda k: vs[k])

def comp(row):
    if row["value"] is np.nan: return row["count"]
    return min(row["value"], row["count"])

df["new_vals"] = df.apply(comp, 1)
# equivalent to 
# df = df[['value', 'count']].min(axis=1)
输出:

new_group  value  count  new_vals
   0   a    2.0      4       2.0
   1   a    2.0      4       2.0
   2   a    2.0      4       2.0
   3   a    2.0      4       2.0
   4   b    NaN      3       3,0
   5   b    NaN      3       3.0
   6   b    NaN      3       3.0
   7   c    6.0      5       5.0
   8   c    6.0      5       5.0       
   9   c    6.0      5       5.0
   10  c    6.0      5       5.0
   11  c    6.0      5       5.0

这里有一个方法。其思想是计算每个
name\u组的行数
,并将其作为一个新列(称为
count
)合并到数据帧中。然后,
new\u vals
将仅作为
计数
列的最小值进行计算:

df = df.merge(df.groupby('name_group').size().reset_index(name='count'), on='name_group')

df['new_vals'] = df[['value', 'count']].min(axis=1)
然后,如果需要,可以使用
df.drop(columns='count',inplace=True)
删除
count
列,以给出:

     name name_group  value  new_vals
0    foo1          a    2.0       2.0
1    foo2          a    2.0       2.0
2    foo3          a    2.0       2.0
3    foo4          a    2.0       2.0
4    bar1          b    NaN       3.0
5    bar2          b    NaN       3.0
6    bar3          b    NaN       3.0
7   buzz1          c    6.0       5.0
8   buzz2          c    6.0       5.0
9   buzz3          c    6.0       5.0
10  buzz4          c    6.0       5.0
11  buzz5          c    6.0       5.0

我将使用
transform
np.where

s=df.groupby('name_group').name_group.transform('count')
df['New']=np.where(s>df.value,df.value,s)
df
Out[13]: 
     name name_group  value  New
0    foo1          a    2.0  2.0
1    foo2          a    2.0  2.0
2    foo3          a    2.0  2.0
3    foo4          a    2.0  2.0
4    bar1          b    NaN  3.0
5    bar2          b    NaN  3.0
6    bar3          b    NaN  3.0
7   buzz1          c    6.0  5.0
8   buzz2          c    6.0  5.0
9   buzz3          c    6.0  5.0
10  buzz4          c    6.0  5.0
11  buzz5          c    6.0  5.0

这似乎不适用于NaN值。将s的值与value列进行比较时出现类型错误。我的错误消息是:“int”和“str”实例之间不支持“>”