按组中的最小值数过滤数据框。

问题描述 投票:2回答:1

我的数据帧结构如下。

#----------------------------------------------------------#
# 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) - 刚刚发现了上面函数中的一些不清楚的地方。还能用,但已经明确了变量名。对不起,给大家带来的困惑!

python-3.x pandas dataframe filtering pandas-groupby
1个回答
0
投票

这将为你做一个小把戏。

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
© www.soinside.com 2019 - 2024. All rights reserved.