如何从数据框中删除空白/NA并将值上移

2025-03-12 08:55:00
admin
原创
16
摘要:问题描述:我有一个巨大的数据框,里面有值和空白/NA。我想从数据框中删除空白,并将下一个值在列中向上移动。考虑下面的示例数据框。import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5,4)) df.iloc[1,2]...

问题描述:

我有一个巨大的数据框,里面有值和空白/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 语句并获得了所需的结果,但有没有更好的方法来完成它。


解决方案 1:

您可以apply使用dropna

np.random.seed(100)
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
print (df)
          0         1         2         3
0 -1.749765       NaN  1.153036 -0.252436
1  0.981321  0.514219       NaN -1.070043
2       NaN       NaN -0.458027  0.435163
3 -0.583595  0.816847  0.672721 -0.104411
4 -0.531280  1.029733 -0.438136 -1.118318

df1 = df.apply(lambda x: pd.Series(x.dropna().values))
print (df1)
          0         1         2         3
0 -1.749765  0.514219  1.153036 -0.252436
1  0.981321  0.816847 -0.458027 -1.070043
2 -0.583595  1.029733  0.672721  0.435163
3 -0.531280       NaN -0.438136 -0.104411
4       NaN       NaN       NaN -1.118318

然后如果需要替换为空白处,会创建混合值(带有数字的字符串),某些功能可能会被破坏:

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

解决方案 2:

方法
这个想法是按 来对列进行排序,numpy以便将s 放在最后。我使用来保留非 内的顺序。最后,我对数组进行切片并重新分配。我接着使用
np.isnan`np.nankind='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速度

简单时间测试

在此处输入图片描述

解决方案 3:

通过 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],
 ...

这里发生的事情是,vmx n,我已经使ab mx都成立n,所以我们要做的是,将i,j和中的每个条目配对a,以获得行b中的元素与元素的值以及列中的元素的值。因此,如果我们有和两者都像上面的矩阵,则返回一个矩阵,其中第一行包含的副本,第二行包含的副本,依此类推。i,j`ai,jbabv[a,b]nv[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  

如果有任何不清楚的地方请告诉我,谢谢:)

解决方案 4:

作为一个熊猫初学者,我无法立即理解@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))

reset_index 的 (drop = True) 可防止旧索引成为新列。

我本来想将此作为对@jezrael 的回答的评论发布,但我的声誉不够高!

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1590  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1361  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   18  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   18  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   19  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用