如何从现有数据生成随机分类数据以填充缺失值 - Python
How to generate random categorical data from existing ones to fill missing values - Python
我有一列缺少分类数据,我试图用同一列中的现有分类变量替换它们。
我不想使用该模式,因为我有太多缺失数据,它会扭曲数据,我宁愿不删除缺失数据的行。
我认为理想的方法是为我的列获取每个变量的比例,然后用现有的分类变量按比例替换缺失的部分。
示例数据框:
ClientId Apple_cat Region Price
0 21 cat_1 Reg_A 5
1 15 cat_2 Nan 6
2 6 Nan Reg_B 7
3 91 cat_3 Reg_A 3
4 45 Nan Reg_C 7
5 89 cat_2 Nan 6
注意:理想情况下,我想避免对每个类别和区域名称进行硬编码。
在 pandas Dataframe 中替换 NaN 的难点在于 fillna() 方法将用相同的数字替换所有 nans,即使您在调用中加入了某种随机性。
import random
df['Apple_cat'].applymap(lambda x: x if not np.isnan(x) else np.random.choice(random.choice(list(x.dropna(axis=0))))
这将用第 1 列其余部分的随机样本替换 Nans。
也许您需要用其他类型的 nan 替换 np.nan。
您可以根据填充行的概率分布来填充缺失值。
import numpy as np
df[‘<your_column_name>’] = df[‘<your_column_name>’].fillna(‘TBD’)
possible_values = df[‘<your_column_name>’].value_counts().to_dict()
possible_values.pop(‘TBD’)
total_items = sum(possible_values.keys())
possible_values = [(k,v) for k,v in possible_values.items()]
prob_dist = [i[1]/total_items for i in possible_values]
def fill_missing_values(item):
if item != ‘TBD’:
index = np.random.choice(np.arange(len(prob_dist), p=prob_dist)
return possible_values[index]
return item
df[‘<your_column_name>’] = df[‘<your_column_name>’].apply(lambda x: fill_missing_values(x))
您可以使用自己的函数来使用简洁的矢量化方法来解决此问题:
def na_randomfill(series):
na_mask = pd.isnull(series) # boolean mask for null values
n_null = na_mask.sum() # number of nulls in the Series
if n_null == 0:
return series # if there are no nulls, no need to resample
# Randomly sample the non-null values from our series
# only sample this Series as many times as we have nulls
fill_values = series[~na_mask].sample(n=n_null, replace=True, random_state=0)
# This ensures our new values will replace NaNs in the correct locations
fill_values.index = series.index[na_mask]
return series.fillna(fill_values)
此解决方案一次适用于 1 个系列,可以这样调用:
out = na_randomfill(df["Apple_cat"])
print(out)
0 cat_1
1 cat_2
2 cat_3
3 cat_3
4 cat_2
5 cat_2
Name: Apple_cat, dtype: object
或者,您可以使用 apply 在每个列上调用它。请注意,由于我们函数中的 if
语句,因此我们在调用 apply
:
之前不需要提前指定 null-containing 列
out = df.apply(na_randomfill)
print(out)
ClientId Apple_cat Region Price
0 21 cat_1 Reg_A 5
1 15 cat_2 Reg_A 6
2 6 cat_3 Reg_B 7
3 91 cat_3 Reg_A 3
4 45 cat_2 Reg_C 7
5 89 cat_2 Reg_C 6
我有一列缺少分类数据,我试图用同一列中的现有分类变量替换它们。
我不想使用该模式,因为我有太多缺失数据,它会扭曲数据,我宁愿不删除缺失数据的行。
我认为理想的方法是为我的列获取每个变量的比例,然后用现有的分类变量按比例替换缺失的部分。
示例数据框:
ClientId Apple_cat Region Price
0 21 cat_1 Reg_A 5
1 15 cat_2 Nan 6
2 6 Nan Reg_B 7
3 91 cat_3 Reg_A 3
4 45 Nan Reg_C 7
5 89 cat_2 Nan 6
注意:理想情况下,我想避免对每个类别和区域名称进行硬编码。
在 pandas Dataframe 中替换 NaN 的难点在于 fillna() 方法将用相同的数字替换所有 nans,即使您在调用中加入了某种随机性。
import random
df['Apple_cat'].applymap(lambda x: x if not np.isnan(x) else np.random.choice(random.choice(list(x.dropna(axis=0))))
这将用第 1 列其余部分的随机样本替换 Nans。 也许您需要用其他类型的 nan 替换 np.nan。
您可以根据填充行的概率分布来填充缺失值。
import numpy as np
df[‘<your_column_name>’] = df[‘<your_column_name>’].fillna(‘TBD’)
possible_values = df[‘<your_column_name>’].value_counts().to_dict()
possible_values.pop(‘TBD’)
total_items = sum(possible_values.keys())
possible_values = [(k,v) for k,v in possible_values.items()]
prob_dist = [i[1]/total_items for i in possible_values]
def fill_missing_values(item):
if item != ‘TBD’:
index = np.random.choice(np.arange(len(prob_dist), p=prob_dist)
return possible_values[index]
return item
df[‘<your_column_name>’] = df[‘<your_column_name>’].apply(lambda x: fill_missing_values(x))
您可以使用自己的函数来使用简洁的矢量化方法来解决此问题:
def na_randomfill(series):
na_mask = pd.isnull(series) # boolean mask for null values
n_null = na_mask.sum() # number of nulls in the Series
if n_null == 0:
return series # if there are no nulls, no need to resample
# Randomly sample the non-null values from our series
# only sample this Series as many times as we have nulls
fill_values = series[~na_mask].sample(n=n_null, replace=True, random_state=0)
# This ensures our new values will replace NaNs in the correct locations
fill_values.index = series.index[na_mask]
return series.fillna(fill_values)
此解决方案一次适用于 1 个系列,可以这样调用:
out = na_randomfill(df["Apple_cat"])
print(out)
0 cat_1
1 cat_2
2 cat_3
3 cat_3
4 cat_2
5 cat_2
Name: Apple_cat, dtype: object
或者,您可以使用 apply 在每个列上调用它。请注意,由于我们函数中的 if
语句,因此我们在调用 apply
:
out = df.apply(na_randomfill)
print(out)
ClientId Apple_cat Region Price
0 21 cat_1 Reg_A 5
1 15 cat_2 Reg_A 6
2 6 cat_3 Reg_B 7
3 91 cat_3 Reg_A 3
4 45 cat_2 Reg_C 7
5 89 cat_2 Reg_C 6