如何使用pandas选择所有非NaN列和非NaN最后一列?

Fan*_*ang 6 python numpy dataframe pandas

如果标题有点令人困惑,请原谅我.

假设我有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
Run Code Online (Sandbox Code Playgroud)

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

0   321
1   900
2   45
Run Code Online (Sandbox Code Playgroud)

另外,我想选择除最后一个非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  
Run Code Online (Sandbox Code Playgroud)

我在网上搜索,发现df.iloc[:, :-1]阅读所有专栏,但最后一篇,并df.iloc[:, -1]阅读最后一栏.

我使用这两个命令的当前结果如下: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  
Run Code Online (Sandbox Code Playgroud)

2.阅读最后一栏

0   NaN
1   900
2   Nan
Run Code Online (Sandbox Code Playgroud)

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

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

Flo*_*oor 7

你可以使用sort来满足你的条件,即

ndf = df.apply(lambda x : sorted(x,key=pd.notnull),1)
Run Code Online (Sandbox Code Playgroud)

这会给

     0      1      2      3      4      5      6
0   NaN    NaN    NaN  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]
Run Code Online (Sandbox Code Playgroud)
0    321.0
1    900.0
3     45.0
Name: 6, dtype: float64
ndf.iloc[:,:-1].apply(lambda x : sorted(x,key=pd.isnull),1)
Run Code Online (Sandbox Code Playgroud)
      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


Div*_*kar 6

第2部分

这是一个矢量化方式,有一些掩蔽来完成选择除最后一个非NaN列之外的所有列的第二个任务 -

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

这是在样本数据帧的修改/通用版本上运行的示例,在第三行中有两个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
Run Code Online (Sandbox Code Playgroud)

第1部分

回到解决第一个案例,只需使用NumPy的高级索引 -

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


piR*_*red 5

选项1

df.stack().groupby(level=0).last()

0    321.0
1    900.0
3     45.0
dtype: float64
Run Code Online (Sandbox Code Playgroud)

选项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.])
Run Code Online (Sandbox Code Playgroud)

选项 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
Run Code Online (Sandbox Code Playgroud)

选项 4
pd.DataFrame.ffill

df.ffill(1).iloc[:, -1]

0    321.0
1    900.0
3     45.0
Name: 6, dtype: float64
Run Code Online (Sandbox Code Playgroud)

解决最后一招

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
Run Code Online (Sandbox Code Playgroud)