【问题标题】:Change Cells in Pandas DataFrame Based on Conditional Slices根据条件切片更改 Pandas DataFrame 中的单元格
【发布时间】:2017-08-27 11:27:03
【问题描述】:

我正在玩 Titanic 数据集,我想做的是用基于 Pclass 的中值填充 Age 列的所有 NaN/Null 值。

这是一些数据:

train

PassengerId Pclass  Age
0   1   3   22
1   2   1   35
2   3   3   26
3   4   1   35
4   5   3   35
5   6   1   NaN
6   7   1   54
7   8   3   2
8   9   3   27
9   10  2   14
10  11  1   Nan

这是我想要的结果:

PassengerId Pclass  Age
0   1   3   22
1   2   1   35
2   3   3   26
3   4   1   35
4   5   3   35
5   6   1   35
6   7   1   54
7   8   3   2
8   9   3   27
9   10  2   14
10  11  1   35

我想出的第一件事是——为了简洁起见,我只为 Pclass 添加了一个等于 1 的切片,而不是包括 2 和 3:

Pclass_1 = train['Pclass']==1

train[Pclass_1]['Age'].fillna(train[train['Pclass']==1]['Age'].median(), inplace=True)

据我了解,此方法创建视图而不是编辑 train 本身(我不太明白这与副本有何不同,或者它们在内存方面是否相似——这是如果可能的话,我很想听听)。我特别喜欢这个关于 View vs Copy, How Do I Tell? 主题的问答,但它不包括我正在寻找的洞察力。

通过查看 Pandas 文档,我了解了为什么要使用 .loc 来避免这个陷阱。但是我似乎无法正确使用语法。

Pclass_1 = train.loc[:,['Pclass']==1]

Pclass_1.Age.fillna(train[train['Pclass']==1]['Age'].median(),inplace=True)

我迷失在索引中。这最终会寻找一个名为False 的列,该列显然不存在。如果没有链式索引,我不知道如何做到这一点。 train.loc[:,train['Pclass']==1] 返回异常 IndexingError: Unalignable boolean Series key provided

【问题讨论】:

  • 一般来说,如果您提供Minimal, Complete, and Verifiable 示例,尤其是可剪切和粘贴示例和预期数据,此类问题将得到更快和更多的回答。
  • 我现在添加了一些来自真实数据框的示例数据。
  • @prdctofchem 我已经根据添加的示例数据更新了我的答案。

标签: python pandas indexing view conditional


【解决方案1】:

在这行,

train.loc[:,['Pclass']==1]

['Pclass'] == 1 部分将列表['Pclass'] 与值1 进行比较,后者返回False。然后.loc[] 被评估为导致错误的.loc[:,False]

我想你的意思是:

train.loc[train['Pclass']==1]

它选择 Pclass 为 1 的所有行。这修复了错误,但仍会为您提供“SettingWithCopyWarning”。

编辑 1

(旧代码已删除)

这是一种使用groupbytransform 来创建Series 的方法 包含每个Pclass 的中位数Age。然后将Series 用作fillna() 的参数,用中位数替换缺失值。使用这种方法将同时更正所有乘客类别,这是 OP 最初要求的。解决方案来自Python-pandas Replace NA with the median or mean of a group in dataframe的答案

import pandas as pd
from io import StringIO

tbl = """PassengerId Pclass  Age
0   1   3   22
1   2   1   35
2   3   3   26
3   4   1   35
4   5   3   35
5   6   1
6   7   1   54
7   8   3   2
8   9   3   27
9   10  2   14
10  11  1
"""

train = pd.read_table(StringIO(tbl), sep='\s+')
print('Original:\n', train)
median_age = train.groupby('Pclass')['Age'].transform('median') #median Ages for all groups
train['Age'].fillna(median_age, inplace=True)
print('\nNaNs replaced with median:\n', train)

代码产生:

 Original:
     PassengerId  Pclass   Age
0             1       3  22.0
1             2       1  35.0
2             3       3  26.0
3             4       1  35.0
4             5       3  35.0
5             6       1   NaN
6             7       1  54.0
7             8       3   2.0
8             9       3  27.0
9            10       2  14.0
10           11       1   NaN

NaNs replaced with median:
     PassengerId  Pclass   Age
0             1       3  22.0
1             2       1  35.0
2             3       3  26.0
3             4       1  35.0
4             5       3  35.0
5             6       1  35.0
6             7       1  54.0
7             8       3   2.0
8             9       3  27.0
9            10       2  14.0
10           11       1  35.0

需要注意的是,这一行,它使用了inplace=True

train['Age'].fillna(median_age, inplace=True)

可以使用.loc替换为赋值:

train.loc[:,'Age'] = train['Age'].fillna(median_age)

【讨论】:

  • 如果我将其应用于多个 Pclass 中具有 NaN 值的数据集,它是否会将它们填充到正确的位置,因为我有一个 GroupBy df?还是在这样做之前我还需要指定匹配 Pclass 值吗?我还想知道在我的情况下,简单地使用聚合方法 .median() 而不是 .transform('median') 是否是更好的选择。
  • @prdctofchem groupby 将在超过 1 个 Pclass 的 NaN 上正常工作。我刚刚做了一个测试,transform() 是必需的 才能工作。您应该以两种方式测试代码以了解为什么transform() 很重要。如果您发现此答案有帮助,请点赞并点击灰色复选标记接受答案。
  • 关于transform()的更多信息:Understanding the Transform Function in Pandas
猜你喜欢
  • 2021-01-25
  • 2021-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-23
  • 1970-01-01
  • 2014-04-04
  • 2022-12-15
相关资源
最近更新 更多