我的数据框如下:
input_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
每个name_group中的每一行都具有相同的“值”,因此在这种情况下,name_group“a”中的每个名称都具有相同的“值”,name_group“b”中的每个名称都具有相同的“值”,等等。
我想创建一个新列“new_vals”,它等于min(“name_group”,“value”列中的行数)。如果任何“name_group”的“value”列中缺少值,则应该只使用该“name_group”中的#行。对于我的示例数据帧,所需的输出是:
output_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_group中的行数,将其与“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])
答案 0 :(得分:2)
我将使用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
答案 1 :(得分:1)
这是一种方法。我们的想法是计算每name_group
行的行数,并将其作为新列(称为count
)合并到数据框中。然后new_vals
将被计算为value
和count
列的最小值:
df = df.merge(df.groupby('name_group').size().reset_index(name='count'), on='name_group')
df['new_vals'] = df[['value', 'count']].min(axis=1)
然后,您可以根据需要删除count
列,使用df.drop(columns='count', inplace=True)
来提供:
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
答案 2 :(得分:0)
一种解决方案是创建一个临时count
,然后比较值。
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