Python 如何删除空白/NA';从dataframe中选择s并将值上移

Python 如何删除空白/NA';从dataframe中选择s并将值上移,python,pandas,numpy,Python,Pandas,Numpy,我有一个巨大的数据框,里面有值和空格/NA。我想删除数据框中的空格,并将列中的下一个值上移。考虑下面的示例数据文件。 import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5,4)) df.iloc[1,2] = np.NaN df.iloc[0,1] = np.NaN df.iloc[2,1] = np.NaN df.iloc[2,0] = np.NaN df 0 1

我有一个巨大的数据框,里面有值和空格/NA。我想删除数据框中的空格,并将列中的下一个值上移。考虑下面的示例数据文件。

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(5,4))
df.iloc[1,2] = np.NaN
df.iloc[0,1] = np.NaN
df.iloc[2,1] = np.NaN
df.iloc[2,0] = np.NaN
df

       0           1           2         3
0   1.857476      NaN      -0.462941   -0.600606
1   0.000267   -0.540645    NaN        0.492480
2   NaN           NaN      -0.803889   0.527973
3   0.566922    0.036393   -1.584926   2.278294
4   -0.243182   -0.221294   1.403478   1.574097
我希望我的输出如下

       0             1             2           3
0   1.857476    -0.540645     -0.462941   -0.600606
1   0.000267     0.036393     -0.803889    0.492480
2   0.566922    -0.221294     -1.584926    0.527973
3   -0.243182                  1.403478    2.278294
4                                          1.574097

我希望删除NaN,并向上移动下一个值<代码>df.shift没有帮助。我尝试了多个循环和if语句,并获得了预期的结果,但有没有更好的方法来完成它。

您可以使用
应用
和:

然后,如果需要替换为空空间,则创建混合值(带数字的字符串)的内容可能会被破坏:

df1 = df.apply(lambda x: pd.Series(x.dropna().values)).fillna('')
print (df1)
          0         1         2         3
0  -1.74977  0.514219   1.15304 -0.252436
1  0.981321  0.816847 -0.458027 -1.070043
2 -0.583595   1.02973  0.672721  0.435163
3  -0.53128           -0.438136 -0.104411
4                               -1.118318

A
numpy
方法
其思想是按
np.isnan
对列进行排序,以便将
np.nan
s放在最后。我使用
kind='mergesort'
在非
np.nan
中保留顺序。最后,我对数组进行切片并重新分配它。我随后用一个
fillna

v = df.values
i = np.arange(v.shape[1])
a = np.isnan(v).argsort(0, kind='mergesort')
v[:] = v[a, i]
print(df.fillna(''))

          0         1         2         3
0   1.85748 -0.540645 -0.462941 -0.600606
1  0.000267  0.036393 -0.803889  0.492480
2  0.566922 -0.221294  -1.58493  0.527973
3 -0.243182             1.40348  2.278294
4                                1.574097
如果您不想在适当的位置更改数据帧

v = df.values
i = np.arange(v.shape[1])
a = np.isnan(v).argsort(0, kind='mergesort')
pd.DataFrame(v[a, i], df.index, df.columns).fillna('')

这一点是为了利用
numpy
s的快速性

原始时间测试


通过piRSquared添加到溶液中: 这会将所有值向左移动,而不是向上移动。
如果不是所有值都是数字,请使用
pd.isnull

v = df.values
a = [[n]*v.shape[1] for n in range(v.shape[0])]
b = pd.isnull(v).argsort(axis=1, kind = 'mergesort')
# a is a matrix used to reference the row index, 
# b is a matrix used to reference the column index
# taking an entry from a and the respective entry from b (Same index), 
# we have a position that references an entry in v
v[a, b]
一点解释:

a
是长度
v.shape[0]
的列表,它看起来像这样:

[[0, 0, 0, 0],
 [1, 1, 1, 1],
 [2, 2, 2, 2],
 [3, 3, 3, 3],
 [4, 4, 4, 4],
 ...
这里发生的事情是,
v
m
x
n
,我已经制作了
a
b
m
x
n
,所以我们正在做的是,将
a
b
中的每个条目配对,以获得第行的元素和
I处的元素值,j
a
中,元素值位于
i,j
的列在
b
中。因此,如果我们的
a
b
都像上面的矩阵,那么
v[a,b]
返回一个矩阵,其中第一行包含
n
v[0][0]
的副本,第二行包含
n个
v[1][1]
的副本,依此类推

在解piRSquared中,他的
i
是一个列表,而不是一个矩阵。因此,该列表用于
v.shape[0]
次,即每行一次。同样,我们本可以做到:

a = [[n] for n in range(v.shape[0])]
# which looks like 
# [[0],[1],[2],[3]...]
# since we are trying to indicate the row indices of the matrix v as opposed to 
# [0, 1, 2, 3, ...] which refers to column indices  
如果有任何不清楚的地方,请告诉我,
谢谢:)

作为一名熊猫初学者,我无法立即理解@jezrael的原因

df.apply(lambda x: pd.Series(x.dropna().values))
但我发现它是通过重置列的索引来工作的。df.apply(默认情况下)逐列工作,将每列视为一个系列。使用df.dropna()会删除NaN,但不会更改其余数字的索引,因此,当此列添加回数据帧时,这些数字会返回到其原始位置,因为它们的索引仍然相同,而空白处会填充NaN,从而重新创建原始数据帧,但什么也没有实现

通过重置列的索引,在这种情况下,通过将序列更改为数组(使用.values)并返回到序列(使用pd.series),只有所有数字(即列底部的数字)后的空格才填充NaN。这同样可以通过以下方式实现:

df.apply(lambda x: x.dropna().reset_index(drop = True))
(drop=True)for reset_index防止旧索引变成新列


我本想在@jezrael的回答上发表评论,但我的代表级别不够高

谢谢,这正是我所看到的。如果数据框中的值不是数字呢?
df.apply(lambda x: x.dropna().reset_index(drop = True))