As mentioned in the comments, you can use transform
to create a series and use it as a boolean mask to drop the desired rows.
# sample data, please always provide in this form so we can paste in our tests
# you could get it with `df.head().to_dict('list')`
df = pd.DataFrame({
'Country': ['Afghanistan', 'Afghanistan', 'Belize', 'Belize'],
'Factor A': [153, 141, None, 50],
'Factor B': [3.575, 3.794, None, 5.956],
'Year': [2011, 2012, 2011, 2012]
})
droprows = (
df.groupby('Country') # group the rows by Country
.transform(lambda x: x.isna().any())
# .transform applies a function and returns the same scalar value
# for all rows in the group
# x.isna() returns True if a cell contains NaN, element-wise
# .any() aggregates and returns a scalar True/False per group
# the line returns a dataframe shaped as df.shape
# with one les column: 'Country'
.any(axis=1) # collapse that result into a single column
)
print(droprows)
# 0 False
# 1 False
# 2 True
# 3 True
# dtype: bool
df = df[~droprows]
print(df)
Output
Country Factor A Factor B Year
0 Afghanistan 153.0 3.575 2011
1 Afghanistan 141.0 3.794 2012