Trim 按 Column/Series 中的序列分组 Pandas 按 NaN 出现

Trim Group by Column/Series Sequence in Pandas by NaN Ocurrence

我有一个数据框如下:

user_id metric_date metric_val1 is_churn
3 2021-01 正确
3 2021-02 正确
3 2021-03 0.4
3 2021-04 0.5
3 2021-05 正确
4 2021-01 0.1
4 2021-02 0.3
4 2021-03 0.2
4 2021-04 正确
4 2021-05 正确

假设还有其他的metric列,但是主要参考的是metric_val1,如何按user_id和trim全部分组在第一个有效 metric_val1 之前具有 NaN 值的行,并且仅保留最后一个 NaN 在 metric_val1 的最后一个有效值之后,输出应该是这样的(假设有效中没有间隙值):

user_id metric_date metric_val1 is_churn
3 2021-03 0.4
3 2021-04 0.5
3 2021-05 正确
4 2021-01 0.1
4 2021-02 0.3
4 2021-03 0.2
4 2021-04 正确

有人可以帮我在 pandas 中有效地做到这一点吗?

请布尔值 select 所有非 Non 值或紧跟在组和掩码中的非 Nan 值之后的 NaN 值。 下面的代码;

df[df.groupby('user_id')['metric_val1'].apply(lambda x : x.notna()|x.isna()&x.shift(1).notna())]



    user_id metric_date  metric_val1  is_churn
2        3     2021-03          0.4     False
3        3     2021-04          0.5     False
4        3     2021-05          NaN      True
5        4     2021-01          0.1     False
6        4     2021-02          0.3     False
7        4     2021-03          0.2     False
8        4     2021-04          NaN      True

如果你有一个大数据帧并且担心内存和速度。可以尝试使用 pyspark。只需实例化一个 pyspark 会话。 Pyspark 是可扩展的;

from  pyspark.sql.functions import *
import pyspark.sql.functions as F
from pyspark.sql import Window
k =Window.partitionBy('user_id').orderBy('user_id','metric_date')
(
  df.withColumn('t', lag('metric_val1').over(k))#Introduce column t which draws immediate preceding columns' value
  .filter((F.col('t')=='NaN')|(F.col('metric_val1')!='NaN'))#Filter out t is NaN or metric_val1 is not NaN
  .drop('t')#drop the temp column
).show()

+-------+-----------+-----------+--------+
|user_id|metric_date|metric_val1|is_churn|
+-------+-----------+-----------+--------+
|      3|    2021-02|        NaN|    true|
|      3|    2021-03|        0.4|   false|
|      3|    2021-04|        0.5|   false|
|      4|    2021-01|        0.1|   false|
|      4|    2021-02|        0.3|   false|
|      4|    2021-03|        0.2|   false|
|      4|    2021-05|        NaN|    true|
+-------+-----------+-----------+--------+