使用 pandas 基于 unique/duplicated 创建不同的数据帧,复制 SAS 的第一个和最后一个功能
Create different dataframe using pandas based on the unique/duplicated with replicating SAS' first and last functionality
这是在python()中复制first
和last
函数创建新变量的数据。
我的示例数据:
df = pd.DataFrame({"col": ['D1986','D1986','H1946','H1946','I1978','I1978','S1987','S1987', 'D1974','L1977'],
"ANOTHER_COL1":['DD','DD','HH','HH','II','II','SS','SS','D','L'],
"COL_WITH_NaN": ['TT','TT','WW','WW',np.nan,np.nan,'ZZ','ZZ',np.nan, np.nan]})
col ANOTHER_COL1 COL_WITH_NaN
0 D1986 DD TT
1 D1986 DD TT
2 H1946 HH WW
3 H1946 HH WW
4 I1978 II NaN
5 I1978 II NaN
6 S1987 SS ZZ
7 S1987 SS ZZ
8 D1974 D NaN
9 L1977 L NaN
在 SAS 中,我可以使用 first
和 last
函数来获取值 D1974
和 L1977
,它们也是唯一值。
我想输出2个数据帧。
期望的输出:
# df_A
col ANOTHER_COL1 COL_WITH_NaN
0 D1986 DD TT
1 D1986 DD TT
2 H1946 HH WW
3 H1946 HH WW
4 S1987 SS ZZ
5 S1987 SS ZZ
6 D1974 D NaN
7 L1977 L NaN
# df_B
col ANOTHER_COL1 COL_WITH_NaN
0 I1978 II NaN
1 I1978 II NaN
以上只是一个简单的例子。完整的SAS
代码是:
DATA df_A df_B;
SET DROP4;
BY ANOTHER_COL1 col DESCENDING COL_WITH_NaN;
IF FIRST.col AND LAST.col THEN OUTPUT df_A;
ELSE IF COL_WITH_NaN = ' ' THEN OUTPUT df_B;
ELSE OUTPUT df_A;
RUN;
我认为 ANOTHER_COL1
和 COL_WITH_NaN
不是问题。其逻辑是先查找唯一的col
条记录输出到df_A
,如果COL_WITH_NaN
中有缺失则输出到df_B
。最后,剩余输出到df_A
.
sas中first
和last
函数的逻辑:group by ANOTHER_COL1、col、COL_WITH_NaN后,SAS自动创建两个变量,FIRST。最后。 SAS 中的临时变量。 SAS 使用第一个的值。最后。用于标识组中第一个和最后一个观察值的变量。
我们可以使用groupby transform
来检查组中的第一个和最后一个值是否为NaN。然后使用掩码创建 df_A
和 df_B
:
m = df.groupby(['col', "ANOTHER_COL1"])['COL_WITH_NaN'].transform(
lambda s: True if len(s) == 1 else (
s.iloc[[0, -1]] # First and last in group
.notna().all() # Both are not NaN
))
df_A = df.loc[m, :].reset_index(drop=True)
df_B = df.loc[~m, :].reset_index(drop=True)
df_A
:
col ANOTHER_COL1 COL_WITH_NaN
0 D1986 DD TT
1 D1986 DD TT
2 H1946 HH WW
3 H1946 HH WW
4 S1987 SS ZZ
5 S1987 SS ZZ
6 D1974 D NaN
7 L1977 L NaN
df_B
:
col ANOTHER_COL1 COL_WITH_NaN
0 I1978 II NaN
1 I1978 II NaN
如果我没听错的话,我认为这应该行得通吗?
df_A = df.loc[df.col.str.contains('D1974|L1977', regex=True) == True]
df_B = df.loc[(df.col.str.contains('D1974|L1977', regex=True) == False)]
看来您需要的是计算组的大小,然后根据组大小进行筛选:
sizes = df.groupby('col').col.transform('size')
df_A = df.loc[sizes == 1]
df_B = df.loc[sizes > 1]
df_A
col
8 D1974
9 L1977
df_B
col
0 D1986
1 D1986
2 H1946
3 H1946
4 I1978
5 I1978
6 S1987
7 S1987
这是在python(first
和last
函数创建新变量的数据。
我的示例数据:
df = pd.DataFrame({"col": ['D1986','D1986','H1946','H1946','I1978','I1978','S1987','S1987', 'D1974','L1977'],
"ANOTHER_COL1":['DD','DD','HH','HH','II','II','SS','SS','D','L'],
"COL_WITH_NaN": ['TT','TT','WW','WW',np.nan,np.nan,'ZZ','ZZ',np.nan, np.nan]})
col ANOTHER_COL1 COL_WITH_NaN
0 D1986 DD TT
1 D1986 DD TT
2 H1946 HH WW
3 H1946 HH WW
4 I1978 II NaN
5 I1978 II NaN
6 S1987 SS ZZ
7 S1987 SS ZZ
8 D1974 D NaN
9 L1977 L NaN
在 SAS 中,我可以使用 first
和 last
函数来获取值 D1974
和 L1977
,它们也是唯一值。
我想输出2个数据帧。
期望的输出:
# df_A
col ANOTHER_COL1 COL_WITH_NaN
0 D1986 DD TT
1 D1986 DD TT
2 H1946 HH WW
3 H1946 HH WW
4 S1987 SS ZZ
5 S1987 SS ZZ
6 D1974 D NaN
7 L1977 L NaN
# df_B
col ANOTHER_COL1 COL_WITH_NaN
0 I1978 II NaN
1 I1978 II NaN
以上只是一个简单的例子。完整的SAS
代码是:
DATA df_A df_B;
SET DROP4;
BY ANOTHER_COL1 col DESCENDING COL_WITH_NaN;
IF FIRST.col AND LAST.col THEN OUTPUT df_A;
ELSE IF COL_WITH_NaN = ' ' THEN OUTPUT df_B;
ELSE OUTPUT df_A;
RUN;
我认为 ANOTHER_COL1
和 COL_WITH_NaN
不是问题。其逻辑是先查找唯一的col
条记录输出到df_A
,如果COL_WITH_NaN
中有缺失则输出到df_B
。最后,剩余输出到df_A
.
sas中first
和last
函数的逻辑:group by ANOTHER_COL1、col、COL_WITH_NaN后,SAS自动创建两个变量,FIRST。最后。 SAS 中的临时变量。 SAS 使用第一个的值。最后。用于标识组中第一个和最后一个观察值的变量。
我们可以使用groupby transform
来检查组中的第一个和最后一个值是否为NaN。然后使用掩码创建 df_A
和 df_B
:
m = df.groupby(['col', "ANOTHER_COL1"])['COL_WITH_NaN'].transform(
lambda s: True if len(s) == 1 else (
s.iloc[[0, -1]] # First and last in group
.notna().all() # Both are not NaN
))
df_A = df.loc[m, :].reset_index(drop=True)
df_B = df.loc[~m, :].reset_index(drop=True)
df_A
:
col ANOTHER_COL1 COL_WITH_NaN
0 D1986 DD TT
1 D1986 DD TT
2 H1946 HH WW
3 H1946 HH WW
4 S1987 SS ZZ
5 S1987 SS ZZ
6 D1974 D NaN
7 L1977 L NaN
df_B
:
col ANOTHER_COL1 COL_WITH_NaN
0 I1978 II NaN
1 I1978 II NaN
如果我没听错的话,我认为这应该行得通吗?
df_A = df.loc[df.col.str.contains('D1974|L1977', regex=True) == True]
df_B = df.loc[(df.col.str.contains('D1974|L1977', regex=True) == False)]
看来您需要的是计算组的大小,然后根据组大小进行筛选:
sizes = df.groupby('col').col.transform('size')
df_A = df.loc[sizes == 1]
df_B = df.loc[sizes > 1]
df_A
col
8 D1974
9 L1977
df_B
col
0 D1986
1 D1986
2 H1946
3 H1946
4 I1978
5 I1978
6 S1987
7 S1987