Как удалить столбцы в соответствии с процентом NAN для данных?

Для некоторых столбцов df, если 80% столбца - NAN.

Какой самый простой код для удаления таких столбцов?

Ответ 1

Вы можете использовать isnull со mean для treshold, а затем удалить столбцы с помощью boolean indexing с помощью loc (поскольку удалить столбцы), также необходимо условие инвертирования - поэтому <.8 означает удаление всех столбцов >=0.8:

df = df.loc[:, df.isnull().mean() < .8]

Образец:

np.random.seed(100)
df = pd.DataFrame(np.random.random((100,5)), columns=list('ABCDE'))
df.loc[:80, 'A'] = np.nan
df.loc[:5, 'C'] = np.nan
df.loc[20:, 'D'] = np.nan

print (df.isnull().mean())
A    0.81
B    0.00
C    0.06
D    0.80
E    0.00
dtype: float64

df = df.loc[:, df.isnull().mean() < .8]
print (df.head())
         B   C         E
0  0.278369 NaN  0.004719
1  0.670749 NaN  0.575093
2  0.209202 NaN  0.219697
3  0.811683 NaN  0.274074
4  0.940030 NaN  0.175410

Если хотите удалить столбцы с минимальными значениями dropna работающими с параметром thresh и axis=1 для удаления столбцов:

np.random.seed(1997)
df = pd.DataFrame(np.random.choice([np.nan,1], p=(0.8,0.2),size=(10,10)))
print (df)
     0   1    2    3    4    5    6    7   8    9
0  NaN NaN  NaN  1.0  1.0  NaN  NaN  NaN NaN  NaN
1  1.0 NaN  1.0  NaN  NaN  NaN  NaN  NaN NaN  NaN
2  NaN NaN  NaN  NaN  NaN  1.0  1.0  NaN NaN  NaN
3  NaN NaN  NaN  NaN  1.0  NaN  NaN  NaN NaN  NaN
4  NaN NaN  NaN  NaN  NaN  1.0  NaN  NaN NaN  1.0
5  NaN NaN  NaN  1.0  1.0  NaN  NaN  1.0 NaN  1.0
6  NaN NaN  NaN  NaN  NaN  NaN  NaN  NaN NaN  NaN
7  NaN NaN  NaN  NaN  NaN  NaN  NaN  NaN NaN  NaN
8  NaN NaN  NaN  NaN  NaN  NaN  NaN  1.0 NaN  NaN
9  1.0 NaN  NaN  NaN  1.0  NaN  NaN  1.0 NaN  NaN

df1 = df.dropna(thresh=2, axis=1)
print (df1)
     0    3    4    5    7    9
0  NaN  1.0  1.0  NaN  NaN  NaN
1  1.0  NaN  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  1.0  NaN  NaN
3  NaN  NaN  1.0  NaN  NaN  NaN
4  NaN  NaN  NaN  1.0  NaN  1.0
5  NaN  1.0  1.0  NaN  1.0  1.0
6  NaN  NaN  NaN  NaN  NaN  NaN
7  NaN  NaN  NaN  NaN  NaN  NaN
8  NaN  NaN  NaN  NaN  1.0  NaN
9  1.0  NaN  1.0  NaN  1.0  NaN

EDIT: для небулевых данных

Общее количество записей NaN в столбце должно составлять менее 80% от общего числа записей:

 df = df.loc[:, df.isnull().sum() < 0.8*df.shape[0]]

Ответ 2

Как указано в комментариях, если вы используете sum() для логического теста, вы можете получить количество вхождений.

Код:

def get_nan_cols(df, nan_percent=0.8):
    threshold = len(df.index) * nan_percent
    return [c for c in df.columns if sum(df[c].isnull()) >= threshold]  

Используется в качестве:

del df[get_nan_cols(df, 0.8)]

Ответ 3

df.dropna(thresh=np.int((100-percent_NA_cols_required)*(len(df.columns)/100)),inplace=True)

В основном pd.dropna принимает число (int) не_значных столбцов, необходимых для удаления этой строки.

Ответ 4

Вот простая функция, которую вы можете использовать напрямую, передавая фрейм данных и порог

def rmissingvaluecol(dff,threshold):
    l = []
    l = list(dff.drop(dff.loc[:,list((100*(dff.isnull().sum()/len(dff.index))>=threshold))].columns, 1).columns.values)
    print("# Columns having more than %s percent missing values:"%threshold,(dff.shape[1] - len(l)))
    print("Columns:\n",list(set(list((dff.columns.values))) - set(l)))
    return l


rmissingvaluecol(df,80) #Here threshold is 80% which means we are going to drop columns having more than 80% of missing values

#output
'''
# Columns having more than 60 percent missing values: 2
Columns:
 ['id', 'location']
'''

Теперь создайте новый фрейм данных, исключая эти столбцы

l = rmissingvaluecol(df,49)
df1 = df[l]

Бонусный шаг

Вы можете найти процент пропущенных значений для каждого столбца (необязательно)

def missing(dff):
    print (round((dff.isnull().sum() * 100/ len(dff)),2).sort_values(ascending=False))

missing(df)

#output
'''
id          83.33
location    83.33
owner       16.67
pets        16.67
dtype: float64
'''