【问题标题】:How to select all non-NaN columns and non-NaN last column using pandas?如何使用熊猫选择所有非 NaN 列和非 NaN 最后一列?
【发布时间】:2017-10-02 04:31:57
【问题描述】:

如果标题有点混乱,请见谅。

假设我有test.h5。下面是使用df.read_hdf('test.h5', 'testdata')读取这个文件的结果

     0     1     2     3     4     5    6
0   123   444   111   321   NaN   NaN  NaN
1   12    234   113   67    21    32   900
3   212   112   543   321   45    NaN  NaN

我想选择最后一个非 Nan 列。我的预期结果是这样的

0   321
1   900
2   45

我还想选择除最后一个非 NaN 列之外的所有列。我的预期结果可能是这样的。它可能在 numpy 数组中,但我还没有找到任何解决方案。

      0     1     2     3     4     5    6
0    123   444   111   
1    12    234   113   67    21    32  
3    212   112   543   321  

我在网上搜索发现df.iloc[:, :-1] 用于阅读除最后一列以外的所有列,df.iloc[:, -1] 用于阅读最后一列。

我当前使用这 2 个命令的结果是这样的: 1. 用于阅读除最后一列以外的所有列

       0     1     2     3     4     5    
0     123   444   111   321   NaN   NaN  
1     12    234   113   67    21    32   
3     212   112   543   321   45    NaN  

2.用于阅读最后一列

0   NaN
1   900
2   Nan

我的问题是,pandas 中是否使用任何命令或查询来解决这些问题?

感谢您的任何帮助和建议。

【问题讨论】:

    标签: python pandas numpy dataframe


    【解决方案1】:

    您可以使用 sorted 来满足您的条件,即

    ndf = df.apply(lambda x : sorted(x,key=pd.notnull),1)
    

    这会给

    0 1 2 3 4 5 6 0 南 南 南 123.0 444.0 111.0 321.0 1 12.0 234.0 113.0 67.0 21.0 32.0 900.0 3 NaN NaN 212.0 112.0 543.0 321.0 45.0

    现在您可以选择最后一列,即

    ndf.iloc[:,-1]
    
    0 321.0 1 900.0 3 45.0 名称:6,数据类型:float64
    ndf.iloc[:,:-1].apply(lambda x : sorted(x,key=pd.isnull),1)
    
    0 1 2 3 4 5 0 123.0 444.0 111.0 NaN NaN NaN 1 12.0 234.0 113.0 67.0 21.0 32.0 3 212.0 112.0 543.0 321.0 NaN NaN

    【讨论】:

      【解决方案2】:

      第 2 部分

      这是一种带有一些掩码的矢量化方式来执行第二个任务,即选择除最后一个非 NaN 列之外的所有列 -

      idx = df.notnull().cumsum(1).idxmax(1).values.astype(int)
      df_out = df.mask(idx[:,None] <= np.arange(df.shape[1]))
      

      这是在示例数据帧的修改/通用版本上运行的示例,第三行有两个 NaN 岛,第二行开始有 NaN 岛 -

      In [181]: df
      Out[181]: 
           0      1      2    3     4     5      6
      0  123  444.0  111.0  321   NaN   NaN    NaN
      1   12    NaN    NaN   67  21.0  32.0  900.0
      3  212    NaN    NaN  321  45.0   NaN    NaN
      
      In [182]: idx = df.notnull().cumsum(1).idxmax(1).values.astype(int)
      
      In [183]: df.mask(idx[:,None] <= np.arange(df.shape[1]))
      Out[183]: 
           0      1      2      3     4     5   6
      0  123  444.0  111.0    NaN   NaN   NaN NaN
      1   12    NaN    NaN   67.0  21.0  32.0 NaN
      3  212    NaN    NaN  321.0   NaN   NaN NaN
      

      第 1 部分

      回到解决第一种情况,简单使用 NumPy 的高级索引 -

      In [192]: df.values[np.arange(len(idx)), idx]
      Out[192]: array([ 321.,  900.,   45.])
      

      【讨论】:

      • 你可以用notnull代替isnull否定
      【解决方案3】:

      选项 1

      df.stack().groupby(level=0).last()
      
      0    321.0
      1    900.0
      3     45.0
      dtype: float64
      

      选项 2
      使用applypd.Series.last_valid_index

      # Thanks to Bharath shetty for the suggestion
      df.apply(lambda x : x[x.last_valid_index()], 1)
      # Old Answer
      # df.apply(pd.Series.last_valid_index, 1).pipe(lambda x: df.lookup(x.index, x))
      
      array([ 321.,  900.,   45.])
      

      选项 3
      通过np.where 和字典理解发挥创意

      pd.Series({df.index[i]: df.iat[i, j] for i, j in zip(*np.where(df.notnull()))})
      
      0    321.0
      1    900.0
      3     45.0
      dtype: float64
      

      选项 4
      pd.DataFrame.ffill

      df.ffill(1).iloc[:, -1]
      
      0    321.0
      1    900.0
      3     45.0
      Name: 6, dtype: float64
      

      解决最后一招

      df.stack().groupby(level=0, group_keys=False).apply(lambda x: x.head(-1)).unstack()
      
             0      1      2      3     4     5
      0  123.0  444.0  111.0    NaN   NaN   NaN
      1   12.0  234.0  113.0   67.0  21.0  32.0
      3  212.0  112.0  543.0  321.0   NaN   NaN
      

      【讨论】:

      • 对于选项 2 只需 df.apply(lambda x : x[x.last_valid_index()],1)
      • 为什么要删除它?
      • 因为我认为它不会回答第二部分。
      • 没错,但仍然很有趣。无论如何,如果您改变主意,很高兴将其删除。
      • 不,先生,我喜欢看你的选项列表。让它在那里
      【解决方案4】:

      使用notnull + iloc + idxmax 作为最后一个非 NaN 值的列名第一个和最后一个lookup

      a = df.notnull().iloc[:,::-1].idxmax(1)
      print (a)
      0    3
      1    6
      3    4
      dtype: object
      
      print (pd.Series(df.lookup(df.index, a)))
      0    321.0
      1    900.0
      2     45.0
      dtype: float64
      

      然后将此值替换为NaNs:

      arr = df.values
      arr[np.arange(len(df.index)),a] = np.nan
      print (pd.DataFrame(arr, index=df.index, columns=df.columns))
             0      1      2      3     4     5   6
      0  123.0  444.0  111.0    NaN   NaN   NaN NaN
      1   12.0  234.0  113.0   67.0  21.0  32.0 NaN
      3  212.0  112.0  543.0  321.0   NaN   NaN NaN
      

      【讨论】:

        【解决方案5】:

        对于那些正在寻找这个特定问题的答案的人,对我来说,我最终使用了 Bharath shetty 给出的答案。为了方便以后访问,我修改了给出的答案,下面是我的代码:

        #assuming you have some csv file with different length of row/column
        #and you want to create h5 file from those csv files
        data_one = [np.loadtxt(file) for file in glob.glob(yourpath + "folder_one/*.csv")]
        data_two = [np.loadtxt(file) for file in glob.glob(yourpath + "folder_two/*.csv")] 
        
        df1 = pd.DataFrame(data_one)
        df2 = pd.DataFrame(data_two)
        
        combine = df1.append(df2, ignore_index=True)
        combine_sort = combine.apply(lambda x : sorted(x, key=pd.notnull), 1)
        combine.to_hdf('test.h5', 'testdata')
        

        阅读

        dataframe = pd.read_hdf('test.h5', 'testdata')
        dataset = dataframe.values
        
        q1 = dataset[:, :-1] # return all column except the last column
        q2 = dataset[:, -1] # return the last column
        

        【讨论】:

          猜你喜欢
          • 2018-05-05
          • 1970-01-01
          • 2023-03-19
          • 2020-05-16
          • 1970-01-01
          • 1970-01-01
          • 2017-08-14
          • 2017-08-25
          • 2016-04-09
          相关资源
          最近更新 更多