如果其他列中的字符串包含列表中的内容,则更新一列中的值
Update Value in one column, if string in other column contains something in list
id name gender
0 13 John Smith 0
1 46 Jim Jeffries 2
2 75 Jennifer Johnson 0
3 37 Sam Adams 0
4 24 John Cleese 0
5 17 Taika Waititi 0
我在 df 中有很多人的名字和性别,取自电影演员的数据库。性别被指定为 1(女性)、2(男性)或 0(未列出)。我想通过名字梳理并冷酷地假设性别。名称将存储在列表中,并手动填写。也许我通过 ID 发现了一个名字不分性别的人,然后自己确定他们是否 male/female,我也想注入它:
m_names = ['John', ...]
f_names = ['Jennifer', ...]
m_ids = ['37', ...]
f_ids = ['', ...]
我很好地控制了 for 循环和 np.where,但我不知道如何逐行通过这个 df。
如果要使用上面的内容,我想要的 return 看起来像:
for index, row in df.iterrows():
if row['gender'] == 0:
if row['name'].str.contains(' |'.join(f_names)) or row['id'].str.contains('|'.join(f_ids)):
return 1
elif row['name'].str.contains(' |'.join(m_names)) or row['id'].str.contains('|'.join(m_ids)):
return 2
print(df)
id name gender
0 13 John Smith 2
1 46 Jim Jeffries 2
2 75 Jennifer Johnson 1
3 37 Sam Adams 2
4 24 John Cleese 2
5 17 Taika Waititi 0
注意“|”前的 space在名字的条件下,避免抓取姓氏的任何部分。
在这一点上,我 运行 对如何格式化我的 if 语句感到困惑。 Python 不喜欢我的格式,并说我的“return”是 'outside function'。如果我将这些更改为
row['gender'] = #
我 运行 遇到了 unicode 问题以及我对 'str' 和 'contains' 的使用。
似乎您需要 np.select
而不需要 for 循环
df['gender'] = np.select([df.name.str.contains(" |".join(m_names)),
df.name.str.contains(" |".join(f_names))],
[2, 1],
default=3)
您可以使用 Pandas 函数 isin
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.isin.html
df.loc[df.name.isin(m_names), 'gender'] = 2
你可以先构造和组合布尔掩码。例如:
m_zero = df['gender'].eq(0)
m_name_female = df['name'].str.contains(' |'.join(f_names))
m_name_male = df['name'].str.contains(' |'.join(m_names))
m_id_female = df['id'].str.contains('|'.join(f_ids))
m_id_male = df['id'].str.contains('|'.join(m_ids))
female_mask = m_zero & (m_name_female | m_id_female)
male_mask = m_zero & (m_name_male | m_id_male)
然后通过pd.DataFrame.loc
应用逻辑:
df.loc[female_mask, 'gender'] = 1
df.loc[male_mask, 'gender'] = 2
或使用嵌套 numpy.where
:
df['gender'] = np.where(female_mask, 1, np.where(male_mask, 2, df['gender']))
或者,如果您希望提供标量默认值,请使用 numpy.select
:
df['gender'] = np.select([female_mask, male_mask], [1, 2], 3)
id name gender
0 13 John Smith 0
1 46 Jim Jeffries 2
2 75 Jennifer Johnson 0
3 37 Sam Adams 0
4 24 John Cleese 0
5 17 Taika Waititi 0
我在 df 中有很多人的名字和性别,取自电影演员的数据库。性别被指定为 1(女性)、2(男性)或 0(未列出)。我想通过名字梳理并冷酷地假设性别。名称将存储在列表中,并手动填写。也许我通过 ID 发现了一个名字不分性别的人,然后自己确定他们是否 male/female,我也想注入它:
m_names = ['John', ...]
f_names = ['Jennifer', ...]
m_ids = ['37', ...]
f_ids = ['', ...]
我很好地控制了 for 循环和 np.where,但我不知道如何逐行通过这个 df。
如果要使用上面的内容,我想要的 return 看起来像:
for index, row in df.iterrows():
if row['gender'] == 0:
if row['name'].str.contains(' |'.join(f_names)) or row['id'].str.contains('|'.join(f_ids)):
return 1
elif row['name'].str.contains(' |'.join(m_names)) or row['id'].str.contains('|'.join(m_ids)):
return 2
print(df)
id name gender
0 13 John Smith 2
1 46 Jim Jeffries 2
2 75 Jennifer Johnson 1
3 37 Sam Adams 2
4 24 John Cleese 2
5 17 Taika Waititi 0
注意“|”前的 space在名字的条件下,避免抓取姓氏的任何部分。
在这一点上,我 运行 对如何格式化我的 if 语句感到困惑。 Python 不喜欢我的格式,并说我的“return”是 'outside function'。如果我将这些更改为
row['gender'] = #
我 运行 遇到了 unicode 问题以及我对 'str' 和 'contains' 的使用。
似乎您需要 np.select
而不需要 for 循环
df['gender'] = np.select([df.name.str.contains(" |".join(m_names)),
df.name.str.contains(" |".join(f_names))],
[2, 1],
default=3)
您可以使用 Pandas 函数 isin
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.isin.html
df.loc[df.name.isin(m_names), 'gender'] = 2
你可以先构造和组合布尔掩码。例如:
m_zero = df['gender'].eq(0)
m_name_female = df['name'].str.contains(' |'.join(f_names))
m_name_male = df['name'].str.contains(' |'.join(m_names))
m_id_female = df['id'].str.contains('|'.join(f_ids))
m_id_male = df['id'].str.contains('|'.join(m_ids))
female_mask = m_zero & (m_name_female | m_id_female)
male_mask = m_zero & (m_name_male | m_id_male)
然后通过pd.DataFrame.loc
应用逻辑:
df.loc[female_mask, 'gender'] = 1
df.loc[male_mask, 'gender'] = 2
或使用嵌套 numpy.where
:
df['gender'] = np.where(female_mask, 1, np.where(male_mask, 2, df['gender']))
或者,如果您希望提供标量默认值,请使用 numpy.select
:
df['gender'] = np.select([female_mask, male_mask], [1, 2], 3)