我的数据帧结构如下。
#----------------------------------------------------------#
# Generate dataframe mock example.
# define categorical column.
grps = pd.DataFrame(['a', 'a', 'a', 'b', 'b', 'b'])
# generate dataframe 1.
df1 = pd.DataFrame([[3, 4, 6, 8, 10, 4],
[5, 7, 2, 8, 9, 6],
[5, 3, 4, 8, 4, 6]]).transpose()
# introduce nan into dataframe 1.
for col in df1.columns:
df1.loc[df1.sample(frac=0.1).index, col] = np.nan
# generate dataframe 2.
df2 = pd.DataFrame([[3, 4, 6, 8, 10, 4],
[5, 7, 2, 8, 9, 6],
[5, 3, 4, 8, 4, 6]]).transpose()
# concatenate categorical column and dataframes.
df = pd.concat([grps, df1, df2], axis = 1)
# Assign column headers.
df.columns = ['Groups', 1, 2, 3, 4, 5, 6]
# Set index as group column.
df = df.set_index('Groups')
# Generate stacked dataframe structure.
test_stack_df = df.stack(dropna = False).reset_index()
# Change column names.
test_stack_df = test_stack_df.rename(columns = {'level_1': 'IDs',
0: 'Values'})
#----------------------------------------------------------#
原始数据框架 - "df "在堆叠之前。
Groups 1 2 3 4 5 6
a 3 5 5 3 5 5
a nan nan 3 4 7 3
a 6 2 nan 6 2 4
b 8 8 8 8 8 8
b 10 9 4 10 9 4
b 4 6 6 4 6 6
我想过滤列,使每组中最少有3个有效值 - 'a' & 'b'. 最终的输出应该只有第4、5、6列。我目前使用的是下面的方法。
# Function to define boolean series.
def filter_vals(test_stack_df, orig_df):
# Reset index.
df_idx_reset = orig_df.reset_index()
# Generate list with size of each 'Group'.
grp_num = pd.value_counts(df_idx_reset['Groups']).to_list()
# Data series for each 'Group'.
expt_class_1 = test_stack_df.head(grp_num[0])
expt_class_2 = test_stack_df.tail(grp_num[1])
# Check if both 'Groups' contain at least 3 values per 'ID'.
valid_IDs = len(expt_class_1['Values'].value_counts()) >=3 & \
len(expt_class_2['Values'].value_counts()) >=3
# Return 'true' or 'false'
return(valid_IDs)
# Apply function to dataframe to generate boolean series.
bool_series = test_stack_df.groupby('IDs').apply(filter_vals, df)
# Transpose original dataframe.
df_T = df.transpose()
# Filter by boolean series & transpose again.
df_filtered = df_T[bool_series].transpose()
我可以通过以下方法以最小的代价实现这个目标 pandas.dataframe.dropna()
然而,这不能考虑不同大小的组,也不能让我指定最小值的数量,而目前的代码却能做到。
对于较大的数据框,即4000+列,代码有点慢,即需要约20秒来完成过滤过程。我已经尝试了其他方法,直接访问原始数据帧,使用 groupby
& transform
但却什么都做不了
有没有更简单快捷的方法?谢谢您的时间!
编辑:03052020 (15:58) - 刚刚发现了上面函数中的一些不清楚的地方。还能用,但已经明确了变量名。对不起,给大家带来的困惑!
这将为你做一个小把戏。
df.notna().groupby(level='Groups').sum(axis=0).ge(3).all(axis=0)
输出:
1 False
2 False
3 False
4 True
5 True
6 True
dtype: bool