大熊猫在每个指数处强制NaN到每列的底部

AGS*_*AGS 6 python pandas

我有一个DataFrame,其中多行跨越每个索引.例如,第一个索引具有这样的结构:

df = pd.DataFrame([["A", "first", 1.0, 1.0, np.NaN],
            [np.NaN, np.NaN, 2.0, np.NaN, 2.0],
            [np.NaN, np.NaN, np.NaN, 3.0, 3.0]],
            columns=["ID", "Name", "val1", "val2", "val3"],
            index=[0, 0, 0])

Out[4]:
    ID   Name  val1  val2  val3
0    A  first     1     1   NaN
0  NaN    NaN     2   NaN     2
0  NaN    NaN   NaN     3     3
Run Code Online (Sandbox Code Playgroud)

我想对每列进行排序/排序,使得NaNs位于该给定索引处每列的底部 - 结果如下所示:

    ID   Name  val1  val2  val3
0    A  first     1     1     2
0  NaN    NaN     2     3     3
0  NaN    NaN   NaN     NaN   NaN
Run Code Online (Sandbox Code Playgroud)

更明确的示例可能如下所示:

df = pd.DataFrame([["A", "first", 1.0, 1.0, np.NaN],
            [np.NaN, np.NaN, 2.0, np.NaN, 2.0],
            [np.NaN, np.NaN, np.NaN, 3.0, 3.0],
            ["B", "second", 4.0, 4.0, np.NaN],
            [np.NaN, np.NaN, 5.0, np.NaN, 5.0],
            [np.NaN, np.NaN, np.NaN, 6.0, 6.0]],
            columns=[ "ID", "Name", "val1", "val2", "val3"],
            index=[0, 0, 0, 1, 1, 1])

Out[5]:
    ID    Name  val1  val2  val3
0    A   first     1     1   NaN
0  NaN     NaN     2   NaN     2
0  NaN     NaN   NaN     3     3
1    B  second     4     4   NaN
1  NaN     NaN     5   NaN     5
1  NaN     NaN   NaN     6     6
Run Code Online (Sandbox Code Playgroud)

期望的结果看起来像这样:

    ID    Name  val1  val2  val3
0    A   first     1     1     2
0  NaN     NaN     2     3     3
0  NaN     NaN   NaN   NaN   NaN
1    B  second     4     4     5
1  NaN     NaN     5     6     6
1  NaN     NaN   NaN   NaN   NaN
Run Code Online (Sandbox Code Playgroud)

我在这个数据帧中有数千行,每个索引最多包含几百行.to_csv在数据框架中,我期望的结果将非常有用.

我试图sort_values(['val1','val2','val3'])在整个数据框架上使用,但这导致索引变得无序.我试图遍历每个索引并进行排序,但这也不会限制NaN每个索引列的底部.我也尝试过fillna另一个值,比如0,但我在这里也没有成功.

虽然我肯定使用它错了,但na_position参数in sort_values并没有产生预期的结果,尽管看起来这可能是想要的.

编辑:

最后的df索引不需要像我的第二个例子那样按数字顺序排列.

通过改变ignore_indexFalse以@的Leb第三代码块的单线,

pd.concat([df[col].sort_values().reset_index(drop=True) for col in df], axis=1, ignore_index=True)
Run Code Online (Sandbox Code Playgroud)

pd.concat([df[col].sort_values().reset_index(drop=True) for col in df], axis=1, ignore_index=False)
Run Code Online (Sandbox Code Playgroud)

通过为给定索引中的所有行创建临时df,我能够完成这项工作 - 不是很漂亮,但它会按照我需要的方式来命令.如果有人(当然)有更好的方法,请告诉我.

new_df = df.ix[0]
new_df = pd.concat([new_df[col].sort_values().reset_index(drop=True) for col in new_df], axis=1, ignore_index=False)
max_index = df.index[-1]
for i in range(1, max_index + 1):
    tmp = df.ix[i]
    tmp = pd.concat([tmp[col].sort_values().reset_index(drop=True) for col in tmp], axis=1, ignore_index=False)
    new_df = pd.concat([new_df,tmp])


In [10]: new_df
Out[10]:
    ID    Name  val1  val2  val3
0    A   first     1     1     2
1  NaN     NaN     2     3     3
2  NaN     NaN   NaN   NaN   NaN
0    B  second     4     4     5
1  NaN     NaN     5     6     6
2  NaN     NaN   NaN   NaN   NaN
Run Code Online (Sandbox Code Playgroud)

DSM*_*DSM 5

我知道 github 上已经讨论过将 nan 推向边缘的问题。对于您的特定框架,我可能会在 Python 级别手动完成,而不必太担心性能。就像是

>>> df.groupby(level=0, sort=False).transform(lambda x: sorted(x,key=pd.isnull))
    ID    Name  val1  val2  val3
0    A   first     1     1     2
0  NaN     NaN     2     3     3
0  NaN     NaN   NaN   NaN   NaN
1    B  second     4     4     5
1  NaN     NaN     5     6     6
1  NaN     NaN   NaN   NaN   NaN
Run Code Online (Sandbox Code Playgroud)

应该管用。请注意,由于sorted是一种稳定排序,并且我们将pd.isnull其用作键(其中 False < True),因此我们将 NaN 推到末尾,同时保留剩余对象的顺序。另请注意,这里我仅根据索引进行分组;我们也可以根据我们想要的任何内容进行分组。