【问题标题】:Replicating SAS' first and last functionality with Python使用 Python 复制 SAS 的第一个和最后一个功能
【发布时间】:2017-09-22 12:48:40
【问题描述】:

我最近迁移到 Python 作为我的主要分析工具,我希望能够复制第一个。 & 最后的。 SAS 中的功能。 SAS 代码如下:

data data.out;
   set data.in;
   if first.ID then flag = 1;
   if last.ID then flag = 1;
run;

输出如下;

ID     flag
AAAA   1
AAAA   0
AAAA   0
AAAA   1
BBBB   1
BBBB   0
BBBB   0
BBBB   1
CCCC   1
CCCC   0
CCCC   1

关于如何在 Python 中执行此操作的任何想法?

【问题讨论】:

  • 你在这里使用pandas 之类的东西还是普通的Python?
  • 这个函数分别用于什么?它在哪里有用?
  • 在 SAS 中,它只标识 groupby 的第一行和最后一行。在 pandas 中进行 groupby 时,该功能基本上是隐含的,并且(几乎?)在我的经验中从来不需要
  • “如何在[其他语言]中复制[语言]”的问题没有得到源语言的标签,每个元。

标签: python pandas dataframe


【解决方案1】:

如果您使用 python 和处理数字,通常会使用pandas

pip install pandas

假设您有一个 CSV 文件,您可以使用 pd.read_csv 加载您的数据。我不会对您的输入做出假设,因此请查看文档。加载数据框后,您可以继续。

import pandas

df = pd.read_csv('file.csv')
df

      ID
0   AAAA
1   AAAA
2   AAAA
3   AAAA
4   BBBB
5   BBBB
6   BBBB
7   BBBB
8   CCCC
9   CCCC
10  CCCC

df['flag'] = ((df.ID != df.ID.shift()) | (df.ID != df.ID.shift(-1))).astype(int)
df
      ID  flag
0   AAAA     1
1   AAAA     0
2   AAAA     0
3   AAAA     1
4   BBBB     1
5   BBBB     0
6   BBBB     0
7   BBBB     1
8   CCCC     1
9   CCCC     0
10  CCCC     1

您也可以使用np.where 来执行此操作(来自 Brad Solomon 的赞赏建议):

df['flag'] = np.where((df.ID != df.ID.shift()) \
                  | (df.ID != df.ID.shift(-1)), 1, 0)
df
      ID  flag
0   AAAA     1
1   AAAA     0
2   AAAA     0
3   AAAA     1
4   BBBB     1
5   BBBB     0
6   BBBB     0
7   BBBB     1
8   CCCC     1
9   CCCC     0
10  CCCC     1

【讨论】:

  • 我认为重要的是要提到用于查找第一次/最后一次出现的列 [ 在上面的示例中,即 col 'ID'] 已排序。否则,这段代码不会给出想要的结果:)
【解决方案2】:

使用熊猫:

import pandas as pd
import numpy as np
df = pd.DataFrame(['AAAA', 'AAAA', 'AAAA', 'AAAA', 
                   'BBBB', 'BBBB', 'BBBB', 'BBBB', 'CCCC', 'CCCC', 'CCCC',],
                  columns=['ID'])

def firstlast(a):
    # For each character grouping set, create a 1d array of 0s padded
    #     with 1s, equal to length of the group.
    a = np.zeros(len(a)-2)
    a = np.pad(a, (1,1), 'constant', constant_values=(1,1))
    return a

df['flag'] = (s.groupby(s).apply(firstlast).apply(pd.Series).stack()
                  .astype(int).values)

print(df)
      ID  flag
0   AAAA     1
1   AAAA     0
2   AAAA     0
3   AAAA     1
4   BBBB     1
5   BBBB     0
6   BBBB     0
7   BBBB     1
8   CCCC     1
9   CCCC     0
10  CCCC     1

@cᴏʟᴅsᴘᴇᴇᴅ 中窃取一点逻辑(这比上述解决方案更聪明)但使用numpy.where

ids = df.ID
df['flag'] = np.where((ids!=ids.shift(1)) | (ids!=ids.shift(-1)), 1, 0)

print(df)
      ID  flag
0   AAAA     1
1   AAAA     0
2   AAAA     0
3   AAAA     1
4   BBBB     1
5   BBBB     0
6   BBBB     0
7   BBBB     1
8   CCCC     1
9   CCCC     0
10  CCCC     1

【讨论】:

  • 请注意,在 SAS 中,BY 语句按照文件中遇到的顺序处理组,并且只处理连续的组(例如 AAA BBB AAA 是 3 个组,而 df.groupby 将考虑 2组)......这可能并不重要,但值得注意......
【解决方案3】:

我觉得这自然是一个 groupby 概念,理想情况下会使用基于 groupby 的方法,尽管基于 shift 的方法当然也没有错(有关更多信息,请参阅下面的简短讨论):

df.loc[ df.groupby('ID',as_index=False).nth([0,-1]).index, 'flag' ] = 1

nth(0) 选择每个 groupby 的第一行,nth(-1) 选择最后一行,nth([0,-1]) 选择两者。这将使其他行丢失,可以很容易地用fillna(0) 填充。

df.flag = df.flag.fillna(0).astype(int)

      ID  flag
0   AAAA     1
1   AAAA     0
2   AAAA     0
3   AAAA     1
4   BBBB     1
5   BBBB     0
6   BBBB     0
7   BBBB     1
8   CCCC     1
9   CCCC     0
10  CCCC     1

关于@JonClements 的评论,请注意,使用 groupby 导致答案对排序顺序不变,而使用 shift 方法将取决于排序顺序(根据具体情况,可能首选其中任何一种)。

【讨论】:

    【解决方案4】:

    很抱歉迟到了。与原始要求的变化。如何使用python程序捕获sas第一个点记录?以下示例基于https://pandas.pydata.org/pandas-docs/stable/getting_started/comparison/comparison_with_sas.html

    第一个 sas 设置: sample_dot_last 和 sample_dot_first 数据集是我需要 python 生成的!

        data sampledata;
        infile cards4;
        input ( x y ) ( 2*$8. )  z record_number;
        cards;
        A            I            10    1     
        A            I            11    2   
        A            I            11    3     
        A            J            15    4     
        B            K            9     5     
        B            K            10    6     
        B            K            10    7     
        B            L            14    8     
        C            I            7     9     
        C            I            19   10     
        C            K            3    11     
        C            K            5    12     
        ;;;;
    
        proc print data= sampledata;
        run;
    
        data sample_dot_last;
         set sampledata;
          by x y z;
          if last.y;
        run;
    
        proc print data= sample_dot_last;
        run;
    
        data sample_dot_first;
         set sampledata;
          by x y z;
          if first.y;
        run;
    
        proc print data= sample_dot_first;
        run;
    

    python 的第二个示例 csv:

        x,y,z,record number
        A,I,10,1
        A,I,11,2
        A,I,11,3
        A,J,15,4
        B,K,9,5
        B,K,10,6
        B,K,10,7
        B,L,14,8
        C,I,7,9
        C,I,19,10
        C,K,3,11
        C,K,5,12
    

    最后是 python 程序,注意 dataframe.groupby( [ ... ] ).last() 或 .first() 产生与 sas 完全相同的输出!

        import numpy as np
        import pandas as pd
        import os
        cwd= os.getcwd()
        print( "cwd={}".format( cwd ))
        df1= pd.read_csv( 'sampledata.csv')
        print( df1 )
    
        df2= df1.groupby( [ 'x', 'y' ]).last()
        print( df2 )
    
        df3= df1.groupby( [ 'x', 'y' ]).first()
        print( df3 )
    

    对不起,不同的问题和答案,希望它有用。

    【讨论】:

      猜你喜欢
      • 2021-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-04
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      相关资源
      最近更新 更多