按条件将数据框分割

7

我正在尝试根据medical_plan_id将我的数据框拆分为两个部分。如果为空,则放入df1中。如果不为空,则放入df2中。

df1 = df_with_medicalplanid[df_with_medicalplanid['medical_plan_id'] == ""]
df2 = df_with_medicalplanid[df_with_medicalplanid['medical_plan_id'] is not ""]

下面的代码可以正常运行,但如果没有空字段,我的代码会引发“ TypeError(“无效类型比较”)”错误。
df1 = df_with_medicalplanid[df_with_medicalplanid['medical_plan_id'] == ""]

如何处理这种情况?

我df_with_medicalplanid看起来像下面这样:

wellthie_issuer_identifier       ...       medical_plan_id
0                   UHC99806       ...                  None
1                   UHC99806       ...                  None

change is not to != ? - Ivan Vinogradov
'medical_plan_id'的数据类型是什么?如果它是整数或浮点数,则与""进行比较会导致类型错误。您可以尝试使用.isnull()代替。 - doctorer
3个回答

14

使用==而不是is来测试相等性

同样,对于不等式,请使用!=而不是is not

is在Python中有特殊的含义。如果两个变量指向同一对象,则返回True,而==检查变量所引用的对象是否相等。另请参见在Python中==is有什么区别吗?

不要重复计算掩码

您正在创建的布尔掩码是逻辑中最昂贵的部分。这也是您想要避免手动重复的逻辑,因为您的第一个和第二个掩码互为反转。因此,您可以使用按位反转~(“波浪号”),也可通过operator.invert访问,来否定现有掩码。

空字符串与空值不同

相对于空字符串,可以通过 == '' 进行测试,但是与 null 值的比较需要使用专门的方法:pd.Series.isnull。这是因为在 Pandas 中使用的 NumPy 数组中,null 值由 np.nan 表示,而 np.nan != np.nan 是设计如此
如果您想用 null 值替换空字符串,可以这样做:
df['medical_plan_id'] = df['medical_plan_id'].replace('', np.nan)

从概念上讲,缺失值应该是空值(np.nan)而不是空字符串。但是,将空值转换为空字符串的反向过程也是可能的:

df['medical_plan_id'] = df['medical_plan_id'].fillna('')

如果差异很重要,你需要了解你的数据并应用适当的逻辑。
半终极解决方案
假设你确实有空值,请计算一个布尔掩码及其反码:
mask = df['medical_plan_id'].isnull()

df1 = df[mask]
df2 = df[~mask]

最终解决方案:避免额外变量

作为程序员,创建额外变量是应该避免的。在这种情况下,你不需要创建两个新变量,你可以使用GroupBydict来给出一个数据帧字典,其中False== 0)和True== 1)键对应于你的掩码:

dfs = dict(tuple(df.groupby(df['medical_plan_id'].isnull())))

那么dfs[0]代表df2dfs[1]代表df1(也可以参考这个相关答案)。以上方法的变体是,您可以放弃字典构建,使用Pandas GroupBy方法:
dfs = df.groupby(df['medical_plan_id'].isnull())

dfs.get_group(0)  # equivalent to dfs[0] from dict solution
dfs.get_group(1)  # equivalent to dfs[1] from dict solution

示例

将以上所有内容付诸实践:

df = pd.DataFrame({'medical_plan_id': [np.nan, '', 2134, 4325, 6543, '', np.nan],
                   'values': [1, 2, 3, 4, 5, 6, 7]})

df['medical_plan_id'] = df['medical_plan_id'].replace('', np.nan)
dfs = dict(tuple(df.groupby(df['medical_plan_id'].isnull())))

print(dfs[0], dfs[1], sep='\n'*2)

   medical_plan_id  values
2           2134.0       3
3           4325.0       4
4           6543.0       5

   medical_plan_id  values
0              NaN       1
1              NaN       2
5              NaN       6
6              NaN       7

我之前使用了类似于 fillna("") 的方法,但我猜这不是正确的做法。如果不使用这个方法,在空值处会出现 None,而半决赛的解决方案正在运行。 - user1896796
抱歉。根据您的评论,我已经更新了问题所涉及的数据框。这是在我删除了fillna("")之后的结果。 - user1896796
@user1896796,那么我提出的解决方案仍然失败了吗?如果是这样,我们仍需要一个[mcve]来演示问题。如果需要帮助,可以参考如何创建可重现的pandas示例 - jpp
@user1896796,很高兴知道你更清楚是否需要额外的变量。 - jpp
喜欢使用 groupby 的想法。感谢指出。 - Jean-Francois T.
显示剩余2条评论

3
另一种方法是解包df.groupby,它返回一个元组迭代器(第一个项目是groupby的元素,第二个项目是数据帧)。

例如:

cond = df_with_medicalplanid['medical_plan_id'] == ''
(_, df1) , (_, df2) = df_with_medicalplanid.groupby(cond)

_在Python中用于标记不需要保留的变量。为了提高可读性,我将代码分成了两行。


完整示例

import pandas as pd 

df_with_medicalplanid = pd.DataFrame({
    'medical_plan_id': ['214212','','12251','12421',''],
    'value': 1
})

cond = df_with_medicalplanid['medical_plan_id'] == ''
(_, df1) , (_, df2) = df_with_medicalplanid.groupby(cond)

print(df1)

返回值:

  medical_plan_id  value
0          214212      1
2           12251      1
3           12421      1

根据@Ecube Analytics的建议,在右侧括号中添加了cond - ChaimG

0
cond = df_with_medicalplanid['medical_plan_id'] == ''
(_, df1) , (_, df2) = df_with_medicalplanid.groupby(cond)
# Anton missed cond in right side bracket

print(df1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接