使用 pandas 基于 unique/duplicated 创建不同的数据帧,复制 SAS 的第一个和最后一个功能

Create different dataframe using pandas based on the unique/duplicated with replicating SAS' first and last functionality

这是在python()中复制firstlast函数创建新变量的数据。

我的示例数据:

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 中,我可以使用 firstlast 函数来获取值 D1974L1977,它们也是唯一值。

我想输出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_COL1COL_WITH_NaN 不是问题。其逻辑是先查找唯一的col条记录输出到df_A,如果COL_WITH_NaN中有缺失则输出到df_B。最后,剩余输出到df_A.

sas中firstlast函数的逻辑:group by ANOTHER_COL1、col、COL_WITH_NaN后,SAS自动创建两个变量,FIRST。最后。 SAS 中的临时变量。 SAS 使用第一个的值。最后。用于标识组中第一个和最后一个观察值的变量。

我们可以使用groupby transform来检查组中的第一个和最后一个值是否为NaN。然后使用掩码创建 df_Adf_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