在 Pandas 中处理 Nulls – 在一列中使用过滤值来填充另外两列中的 nan
Posted
技术标签:
【中文标题】在 Pandas 中处理 Nulls – 在一列中使用过滤值来填充另外两列中的 nan【英文标题】:Handling Nulls in Pandas – Use filtered values in one column to fill nan in two other columns 【发布时间】:2020-12-28 06:10:46 【问题描述】:这是对我发布的a recent question/answer 的澄清/重述。我想知道我的解决方案是否是最简单或最有效的选择。
问:包含一些缺失值的单独列
我有一个包含三列的数据框:df.location
,以字符串形式使用逗号分隔的经纬度坐标,df.target
,一个目标变量,其当前格式为浮点数,整数介于 1 和 5 之间,df.null
,一个主要是 nan 但也混合了经纬度坐标并在 1 到 5 之间浮动的列。
这是一个例子 df:
df = pd.DataFrame(
'target': 0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: 4.0, 6: 5.0, 7: 4.0, 8: 4.0, 9: 4.0,
'location': 0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: '41.69230795,-72.26691314', 6: '41.70631764,-70.2868794', 7: '41.70687995,-70.28684036', 8: '41.70598417,-70.28671793', 9: '41.69220757,-70.26687248',
'null': 0: '41.70477575,-70.28844073', 1: '2', 2: '41.70637091,-70.28704334', 3: '4', 4: '3', 5: nan, 6: nan, 7: nan, 8: nan, 9: nan
)
对于df.null
中存在非缺失值的每一行,df.target
和df.location
中的值都缺失。 (我不知道这是怎么发生的,但我检查了我读入 Pandas 数据帧的原始 JSON,果然当位置和目标丢失时,这个空键经常弹出。)这是我的 Jupyter 的 Seaborn 热图的屏幕截图笔记本来说明:
假设df.location
和df.target
中的部分或全部缺失值在df.null
中是否安全?如果是这样,如何根据它们是经纬字符串还是目标浮点数将这些值移动到适当的列中?
A:使用 fillna() 和 str.contains() 处理
这是迄今为止我最好的答案——让我知道你的想法。基本上我只是用fillna(value=df.null)
来填充df.location
和df.target
中的所有缺失值:
df.target.fillna(
value=df.null,
inplace=True
)
df.location.fillna(
value=df.null,
inplace=True
)
然后我使用正则表达式对df.target
和df.location
进行布尔过滤,并将所有不适当的值设置为np.nan
:
# Converting columns to type str so string methods work
df = df.astype(str)
# Using regex to change values that don't belong in column to NaN
regex = '[,]'
df.loc[df.target.str.contains(regex), 'target'] = np.nan
regex = '^\d\.?0?$'
df.loc[df.location.str.contains(regex), 'location'] = np.nan
# Returning `df.level` to float datatype (str is the correct
# datatype for `df.location`
df.target.astype(float)
有没有更好的方法来做到这一点?
编辑:更改了 fillna() 单元格代码以使其正常工作。
【问题讨论】:
【参考方案1】:假设 df.location 和 df.target 中的部分或全部缺失值在 df.null 中是否安全?
这取决于初始数据。如果您有太多要手动检查的内容,您将无法知道。您可以在转换后检查数据框,但不确定。
我用fillna(value=)
的新用法(感谢这个,我不太理解),我找到了一个更快的方法来写它:
df = pd.DataFrame(
'target': 0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: 4.0, 6: 5.0, 7: 4.0, 8: 4.0, 9: 4.0,
'location': 0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: '41.69230795,-72.26691314', 6: '41.70631764,-70.2868794', 7: '41.70687995,-70.28684036', 8: '41.70598417,-70.28671793', 9: '41.69220757,-70.26687248',
'null': 0: '41.70477575,-70.28844073', 1: '2', 2: '41.70637091,-70.28704334', 3: '4', 4: '3', 5: nan, 6: nan, 7: nan, 8: nan, 9: nan
).assign(
target=lambda x: x.target.fillna(value=pd.to_numeric(x.null, errors='coerce')),
location=lambda x: x.location.fillna(
value=x.loc[pd.to_numeric(x.null, errors='coerce').isnull(), 'null']
)
).drop('null', axis='columns')
前面的代码给出了以下数据框:
location target
0 41.70477575,-70.28844073 NaN
1 NaN 2.0
2 41.70637091,-70.28704334 NaN
3 NaN 4.0
4 NaN 3.0
5 41.69230795,-72.26691314 4.0
6 41.70631764,-70.2868794 5.0
7 41.70687995,-70.28684036 4.0
8 41.70598417,-70.28671793 4.0
9 41.69220757,-70.26687248 4.0
您可以通过检查来检查 null 和 target 中是否没有值:
高于 5 的值(如果有,则您的假设为假,如果没有,则仍不确定 :-)) 位置列中的昏迷数。我离开了结果相同的旧版本。
以前的版本
这里的转换没有正则表达式:
import pandas as pd
from numpy import nan
df = pd.DataFrame(
'target': 0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: 4.0, 6: 5.0, 7: 4.0, 8: 4.0, 9: 4.0,
'location': 0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: '41.69230795,-72.26691314', 6: '41.70631764,-70.2868794', 7: '41.70687995,-70.28684036', 8: '41.70598417,-70.28671793', 9: '41.69220757,-70.26687248',
'null': 0: '41.70477575,-70.28844073', 1: '2', 2: '41.70637091,-70.28704334', 3: '4', 4: '3', 5: nan, 6: nan, 7: nan, 8: nan, 9: nan
).assign(
# use the conversion to numeric of the null column in order to find values
# going to target and to location
new_target=lambda x: pd.to_numeric(x['null'], errors='coerce'),
new_location=lambda x: x.loc[pd.to_numeric(x['null'], errors='coerce').isnull(), 'null'],
).assign(
target_without_nan=lambda x: x.new_target.fillna(0.0),
new_location=lambda x: x.new_location.fillna(''),
target=lambda x: (x.target_without_nan + x.target.fillna(0.0)).loc[~(x.target.isnull() & x.new_target.isnull())],
location=lambda x: x.location.fillna('').str.cat(x.new_location.astype(str)).replace('', nan)
).loc[:, ['location', 'target']]
我使用来自this answer 的求和和连接技巧来替换初始列的nan
值。我还保留了nan
值,这些值在最后一次分配目标时无法用.loc
替换。
【讨论】:
感谢您的回答!给了我很多可以玩的东西——我以前没有用过 .assign()。我在 OP 中编辑了 fillna() 单元格以使其正常工作——我过去在 dfs 或 for 循环中填充 nan 时遇到过问题,并认为我在测试时已经绕过它,但它通过了。跨度> 我编辑我的答案是因为我找到了一种更短、更好的方法来完成同样的工作。我留下旧答案的代码。以上是关于在 Pandas 中处理 Nulls – 在一列中使用过滤值来填充另外两列中的 nan的主要内容,如果未能解决你的问题,请参考以下文章