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|
+-------+-----------+-----------+--------+
我有一个数据框如下:
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|
+-------+-----------+-----------+--------+