Pandas:删除少于 2 个非零值的项目

Pandas: Remove Items who has less than 2 non-zero values

我有一个数据框,其中包含所有 317 个不同的 ProductCode 和每周销售数量列的连续 30 个每周日期,如下所示:

Date    ProductCode Weekly_Units_Sold
2015-08-09   1       46.0
2015-08-09   2       46.0
2015-08-09   3       31.0
 ...         ...      ...
2015-08-09   317     47.0
2015-08-16   1       0
2015-08-16   2       46.0
2015-08-16   3       31.0
  ...       ...
2015-08-16  317      75.0
2015-08-23   1       0.0
2015-08-23   2       90.0
2015-08-23   3       175.0
....         ...   
2015-08-23  317      20.0
 ....      ...       ..
2015-12-27   1       0.0
2015-12-27   2       30.0
2015-12-27   3       150.0
....         ...   
2015-12-27  317      20.0

我正在尝试检查每个 ProductCode 的 Weekly_Units_Sold,是否有任何 ProductCode 在 Weekly_Units_Sold 中具有少于 2 个非零值;代码应该删除属于检测到的 ProductCode 的所有行。

假设已检测到 ProductCode 1 在 Weekly_Units_Sold 列值中只有 1 个非零值,其 29 个其他值均为 0 。想要从数据框中删除属于 ProductCode 1 的所有 30 行,

Date    ProductCode Weekly_Units_Sold
2015-08-09   2       46.0
2015-08-09   3       31.0
 ...         ...      ...
2015-08-09   317     47.0
2015-08-16   2       46.0
2015-08-16   3       31.0
  ...       ...
2015-08-16  317      75.0
2015-08-23   2       90.0
2015-08-23   3       175.0
....         ...   
2015-08-23  317      20.0
 ....      ...       ..
2015-12-27   2       30.0
2015-12-27   3       150.0
....         ...   
2015-12-27  317      20.0

做 tihs 的最佳 Pythonistic 方法是什么? 谢谢!

我对您的示例数据进行了一些编辑,以便构建一个工作示例。

Date    ProductCode Weekly_Units_Sold
2015-08-09   1       46.0
2015-08-09   2       46.0
2015-08-09   3       31.0
2015-08-09   317     47.0
2015-08-16   1       0
2015-08-16   2       46.0
2015-08-16   3       31.0
2015-08-16  317      75.0
2015-08-23   1       0.0
2015-08-23   2       90.0
2015-08-23   3       175.0
2015-08-23  317      20.0
2015-12-27   1       0.0
2015-12-27   2       30.0
2015-12-27   3       150.0
2015-12-27  317      20.0

这里我们从上述数据的 pd.read_clipboard() 开始。

df = pd.read_clipboard()

print(df)

Date    ProductCode Weekly_Units_Sold
0   2015-08-09  1   46.0
1   2015-08-09  2   46.0
2   2015-08-09  3   31.0
3   2015-08-09  317 47.0
4   2015-08-16  1   0.0
5   2015-08-16  2   46.0
6   2015-08-16  3   31.0
7   2015-08-16  317 75.0
8   2015-08-23  1   0.0
9   2015-08-23  2   90.0
10  2015-08-23  3   175.0
11  2015-08-23  317 20.0
12  2015-12-27  1   0.0
13  2015-12-27  2   30.0
14  2015-12-27  3   150.0
15  2015-12-27  317 20.0

我们按 ProductCode 分组并创建 Weekly_Units_Sold 列中所有 Weekly_Units_Sold 值的字符串列表。

df_gb = df.groupby(['ProductCode'])['Weekly_Units_Sold'].apply(list).to_frame()

print(df_gb)
            Weekly_Units_Sold
ProductCode 
1           [46.0, 0.0, 0.0, 0.0]
2           [46.0, 46.0, 90.0, 30.0]
3           [31.0, 31.0, 175.0, 150.0]
317         [47.0, 75.0, 20.0, 20.0]

接下来我们可以使用 lambda 和 np.count_nonzero 为产品代码提供 < 2 个非零值的布尔值。

df_gb['non_zero_lt_two'] = df_gb['Weekly_Units_Sold'].apply(lambda x: True if np.count_nonzero(np.array(x)) < 2 else False)

打印(df_gb)

        Weekly_Units_Sold           non_zero_lt_two
ProductCode     
1       [46.0, 0.0, 0.0, 0.0]       True
2       [46.0, 46.0, 90.0, 30.0]    False
3       [31.0, 31.0, 175.0, 150.0]  False
317     [47.0, 75.0, 20.0, 20.0]    False

然后我们可以将真值行变成一个列表。

prod_code_list = df_gb.index[df_gb['non_zero_lt_two'] == True].tolist()

然后最后从原始 df 中删除所需的行。

df = df[~df['ProductCode'].isin(prod_code_list)]

print(df)

Date    ProductCode Weekly_Units_Sold
1   2015-08-09  2   46.0
2   2015-08-09  3   31.0
3   2015-08-09  317 47.0
5   2015-08-16  2   46.0
6   2015-08-16  3   31.0
7   2015-08-16  317 75.0
9   2015-08-23  2   90.0
10  2015-08-23  3   175.0
11  2015-08-23  317 20.0
13  2015-12-27  2   30.0
14  2015-12-27  3   150.0
15  2015-12-27  317 20.0