pandas 如果包含一个空格,熊猫将名称列拆分为名字和姓氏

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38437847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 01:36:31  来源:igfitidea点击:

Pandas split name column into first and last name if contains one space

pythonpandas

提问by unpairestgood

Let's say I have a pandas DataFrame containing names like so:

假设我有一个包含如下名称的 Pandas DataFrame:

name_df = pd.DataFrame({'name':['Hyman Fine','Kim Q. Danger','Jane Smith', 'Juan de la Cruz']})

name_df = pd.DataFrame({'name':['Hyman Fine','Kim Q. Danger','Jane Smith', 'Juan de la Cruz']})

    name
0   Hyman Fine
1   Kim Q. Danger
2   Jane Smith
3   Juan de la Cruz

and I want to split the namecolumn into first_nameand last_nameIF there is one space in the name. Otherwise I want the full name to be shoved into first_name.

我想分裂name柱成first_namelast_name是否有在名称中有一个空格。否则,我希望将全名放入first_name.

So the final DataFrame should look like:

所以最终的 DataFrame 应该是这样的:

  first_name     last_name
0 Hyman           Fine
1 Kim Q. Danger
2 Jane           Smith
3 Juan de la Cruz

I've tried to accomplish this by first applying the following function to return names that can be split into first and last name:

我试图通过首先应用以下函数来返回可以拆分为名字和姓氏的名称来实现此目的:

def validate_single_space_name(name: str) -> str:
    pattern = re.compile(r'^.*( ){1}.*$')
    match_obj = re.match(pattern, name)
    if match_obj:
        return name
    else:
        return None

However applying this function to my original name_df, leads to an empty DataFrame, not one populated by names that can be split and Nones.

但是,将此函数应用于我原来的 name_df 会导致一个空的 DataFrame,而不是由可以拆分的名称和 Nones 填充的 DataFrame。

Help getting my current approach to work, or solutions invovling a different approach would be appreciated!

帮助使我当前的工作方法,或涉及不同方法的解决方案将不胜感激!

回答by EdChum

You can use str.splitto split the strings, then test the number of splits using str.lenand use this as a boolean mask to assign just those rows with the last component of the split:

您可以使用str.split拆分字符串,然后使用测试拆分的数量str.len并将其用作布尔掩码以仅分配具有拆分的最后一个组件的那些行:

In [33]:
df.loc[df['name'].str.split().str.len() == 2, 'last name'] = df['name'].str.split().str[-1]
df

Out[33]:
              name last name
0        Hyman Fine      Fine
1    Kim Q. Danger       NaN
2       Jane Smith     Smith
3  Juan de la Cruz       NaN

EDIT

编辑

You can call splitwith param expand=Truethis will only populate where the name lengths are exactly 2 names:

您可以split使用 param调用expand=True这只会填充名称长度恰​​好为 2 个名称的位置:

In [16]:
name_df[['first_name','last_name']] = name_df['name'].loc[name_df['name'].str.split().str.len() == 2].str.split(expand=True)
name_df

Out[16]:
              name first_name last_name
0        Hyman Fine       Hyman      Fine
1    Kim Q. Danger        NaN       NaN
2       Jane Smith       Jane     Smith
3  Juan de la Cruz        NaN       NaN

You can then replace the missing first names using fillna:

然后,您可以使用fillna以下命令替换缺少的名字:

In [17]:
name_df['first_name'].fillna(name_df['name'],inplace=True)
name_df
?
Out[17]:
              name       first_name last_name
0        Hyman Fine             Hyman      Fine
1    Kim Q. Danger    Kim Q. Danger       NaN
2       Jane Smith             Jane     Smith
3  Juan de la Cruz  Juan de la Cruz       NaN

回答by ivansabik

I was having some issues with IndexError: list index out of rangebecause the names could be test, kkand other weird user input. So ended up with something like this:

我遇到了一些问题,IndexError: list index out of range因为名称可能是testkk以及其他奇怪的用户输入。所以最终得到了这样的东西:

items['fullNameSplitLength'] = items['fullName'].str.split().str.len()
items['firstName'] = items['lastName'] = ''
items.loc[
  items['fullNameSplitLength'] >= 1,
  'firstName'
] = items.loc[items['fullNameSplitLength'] >= 1]['fullName'].str.split().str[0]
items.loc[
  items['fullNameSplitLength'] >= 2,
  'lastName'
] = items.loc[items['fullNameSplitLength'] >= 2]['fullName'].str.split().str[-1]