如何将数据框字符串列拆分为两列?

2024-11-26 08:37:00
admin
原创
174
摘要:问题描述:我有一个带有一列(字符串)的数据框,我想将其拆分为两列(字符串),一列标题为 ' fips',另一列标题为'row'我的数据框df如下所示: row 0 00000 UNITED STATES 1 01000 ALABAMA 2 01001 Autauga Cou...

问题描述:

我有一个带有一列(字符串)的数据框,我想将其拆分为两列(字符串),一列标题为 ' fips',另一列标题为'row'

我的数据框df如下所示:

          row
0    00000 UNITED STATES
1    01000 ALABAMA
2    01001 Autauga County, AL
3    01003 Baldwin County, AL
4    01005 Barbour County, AL

我不知道如何使用df.row.str[:]来实现拆分行单元格的目标。我可以使用df['fips'] = hello添加新列并用 填充它hello。有什么想法吗?

         fips       row
0    00000 UNITED STATES
1    01000 ALABAMA 
2    01001 Autauga County, AL
3    01003 Baldwin County, AL
4    01005 Barbour County, AL

解决方案 1:

TL;DR 版本:

对于简单情况:

  • 我有一个带分隔符的文本列,我想要两列

最简单的解决方案是:

df[['A', 'B']] = df['AB'].str.split(' ', n=1, expand=True)

expand=True如果字符串的拆分数量不均匀并且您想要None替换缺失的值,则必须使用。

请注意,无论哪种情况,.tolist()方法都不是必需的。也不是zip()

详细:

Andy Hayden 的解决方案最出色地展示了该方法的威力str.extract()

但是对于按已知分隔符进行的简单拆分(例如,按破折号拆分或按空格拆分),该.str.split()方法就足够了1。它对字符串列(系列)进行操作,并返回列表列(系列):

>>> import pandas as pd
>>> df = pd.DataFrame({'AB': ['A1-B1', 'A2-B2']})
>>> df

      AB
0  A1-B1
1  A2-B2
>>> df['AB_split'] = df['AB'].str.split('-')
>>> df

      AB  AB_split
0  A1-B1  [A1, B1]
1  A2-B2  [A2, B2]

1:如果您不确定的前两个参数的作用,我建议您参阅该方法的纯 Python 版本的.str.split()文档。

但是你该如何从:

  • 包含双元素列表的列

到:

  • 两列,每列包含列表的相应元素?

好吧,我们需要仔细看看.str一列的属性。

它是一个神奇的对象,用于收集将列中每个元素视为字符串的方法,然后尽可能高效地在每个元素中应用相应的方法:

>>> upper_lower_df = pd.DataFrame({"U": ["A", "B", "C"]})
>>> upper_lower_df

   U
0  A
1  B
2  C
>>> upper_lower_df["L"] = upper_lower_df["U"].str.lower()
>>> upper_lower_df

   U  L
0  A  a
1  B  b
2  C  c

但它也有一个“索引”接口,用于通过索引获取字符串的每个元素:

>>> df['AB'].str[0]

0    A
1    A
Name: AB, dtype: object

>>> df['AB'].str[1]

0    1
1    2
Name: AB, dtype: object

当然,这个索引接口.str并不真正关心它索引的每个元素是否实际上是一个字符串,只要它可以被索引就可以了,所以:

>>> df['AB'].str.split('-', 1).str[0]

0    A1
1    A2
Name: AB, dtype: object

>>> df['AB'].str.split('-', 1).str[1]

0    B1
1    B2
Name: AB, dtype: object

然后,利用 Python 元组解包迭代器来做这件事很简单

>>> df['A'], df['B'] = df['AB'].str.split('-', n=1).str
>>> df

      AB  AB_split   A   B
0  A1-B1  [A1, B1]  A1  B1
1  A2-B2  [A2, B2]  A2  B2

当然,通过拆分一列字符串来获取 DataFrame 非常有用,该.str.split()方法可以使用以下参数为您完成此操作expand=True

>>> df['AB'].str.split('-', n=1, expand=True)

    0   1
0  A1  B1
1  A2  B2

因此,实现我们想要的目标的另一种方法是:

>>> df = df[['AB']]
>>> df

      AB
0  A1-B1
1  A2-B2

>>> df.join(df['AB'].str.split('-', n=1, expand=True).rename(columns={0:'A', 1:'B'}))

      AB   A   B
0  A1-B1  A1  B1
1  A2-B2  A2  B2

expand=True版本虽然更长,但与元组解包方法相比具有明显的优势。元组解包不能很好地处理不同长度的拆分:

>>> df = pd.DataFrame({'AB': ['A1-B1', 'A2-B2', 'A3-B3-C3']})
>>> df
         AB
0     A1-B1
1     A2-B2
2  A3-B3-C3
>>> df['A'], df['B'], df['C'] = df['AB'].str.split('-')
Traceback (most recent call last):
  [...]    
ValueError: Length of values does not match length of index
>>> 

但通过放置在没有足够“分割”的列中expand=True可以很好地处理它:None

>>> df.join(
...     df['AB'].str.split('-', expand=True).rename(
...         columns={0:'A', 1:'B', 2:'C'}
...     )
... )
         AB   A   B     C
0     A1-B1  A1  B1  None
1     A2-B2  A2  B2  None
2  A3-B3-C3  A3  B3    C3

解决方案 2:

可能有更好的方法,但这是一种方法:

                            row
    0       00000 UNITED STATES
    1             01000 ALABAMA
    2  01001 Autauga County, AL
    3  01003 Baldwin County, AL
    4  01005 Barbour County, AL
df = pd.DataFrame(df.row.str.split(' ',1).tolist(),
                                 columns = ['fips','row'])
   fips                 row
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

解决方案 3:

您可以使用正则表达式模式非常巧妙地提取出不同的部分:

In [11]: df.row.str.extract('(?P<fips>d{5})((?P<state>[A-Z ]*$)|(?P<county>.*?), (?P<state_code>[A-Z]{2}$))')
Out[11]: 
    fips                    1           state           county state_code
0  00000        UNITED STATES   UNITED STATES              NaN        NaN
1  01000              ALABAMA         ALABAMA              NaN        NaN
2  01001   Autauga County, AL             NaN   Autauga County         AL
3  01003   Baldwin County, AL             NaN   Baldwin County         AL
4  01005   Barbour County, AL             NaN   Barbour County         AL

[5 rows x 5 columns]

解释一下有点长的正则表达式:

(?P<fips>d{5})
  • 匹配五位数字(d)并为其命名"fips"

下一部分:

((?P<state>[A-Z ]*$)|(?P<county>.*?), (?P<state_code>[A-Z]{2}$))

|是否执行以下任一操作( ):

(?P<state>[A-Z ]*$)
  • 匹配任意数量 ( *) 的大写字母或空格 ( ) 并在字符串结尾之前[A-Z ]命名它( ),"state"`$`

或者

(?P<county>.*?), (?P<state_code>[A-Z]{2}$))
  • 匹配其他任何内容 ( .*) 然后

  • 逗号和空格

  • state_code匹配字符串结尾之前的两位数字( $)。

在示例中:

请注意,前两行命中“州”(在县和 state_code 列中留下 NaN),而后三行命中县、state_code(在州列中留下 NaN)。

解决方案 4:

df[['fips', 'row']] = df['row'].str.split(' ', n=1, expand=True)

解决方案 5:

您可以使用str.split空格(默认分隔符)和参数expand=TrueDataFrame分配给新列:

df = pd.DataFrame({'row': ['00000 UNITED STATES', '01000 ALABAMA', 
                           '01001 Autauga County, AL', '01003 Baldwin County, AL', 
                           '01005 Barbour County, AL']})
print (df)
                        row
0       00000 UNITED STATES
1             01000 ALABAMA
2  01001 Autauga County, AL
3  01003 Baldwin County, AL
4  01005 Barbour County, AL



df[['a','b']] = df['row'].str.split(n=1, expand=True)
print (df)
                        row      a                   b
0       00000 UNITED STATES  00000       UNITED STATES
1             01000 ALABAMA  01000             ALABAMA
2  01001 Autauga County, AL  01001  Autauga County, AL
3  01003 Baldwin County, AL  01003  Baldwin County, AL
4  01005 Barbour County, AL  01005  Barbour County, AL

如果需要修改,删除原来的列DataFrame.pop

df[['a','b']] = df.pop('row').str.split(n=1, expand=True)
print (df)
       a                   b
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

类似的东西有:

df[['a','b']] = df['row'].str.split(n=1, expand=True)
df = df.drop('row', axis=1)
print (df)

       a                   b
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

如果出现错误:

#remove n=1 for split by all whitespaces
df[['a','b']] = df['row'].str.split(expand=True)

ValueError:列的长度必须与键的长度相同

您可以检查,它返回 4 列DataFrame,而不仅仅是 2 列:

print (df['row'].str.split(expand=True))
       0        1        2     3
0  00000   UNITED   STATES  None
1  01000  ALABAMA     None  None
2  01001  Autauga  County,    AL
3  01003  Baldwin  County,    AL
4  01005  Barbour  County,    AL

然后解决方案是DataFrame通过以下方式添加新的join

df = pd.DataFrame({'row': ['00000 UNITED STATES', '01000 ALABAMA', 
                           '01001 Autauga County, AL', '01003 Baldwin County, AL', 
                           '01005 Barbour County, AL'],
                    'a':range(5)})
print (df)
   a                       row
0  0       00000 UNITED STATES
1  1             01000 ALABAMA
2  2  01001 Autauga County, AL
3  3  01003 Baldwin County, AL
4  4  01005 Barbour County, AL

df = df.join(df['row'].str.split(expand=True))
print (df)

   a                       row      0        1        2     3
0  0       00000 UNITED STATES  00000   UNITED   STATES  None
1  1             01000 ALABAMA  01000  ALABAMA     None  None
2  2  01001 Autauga County, AL  01001  Autauga  County,    AL
3  3  01003 Baldwin County, AL  01003  Baldwin  County,    AL
4  4  01005 Barbour County, AL  01005  Barbour  County,    AL

删除原始列(如果还有其他列):

df = df.join(df.pop('row').str.split(expand=True))
print (df)
   a      0        1        2     3
0  0  00000   UNITED   STATES  None
1  1  01000  ALABAMA     None  None
2  2  01001  Autauga  County,    AL
3  3  01003  Baldwin  County,    AL
4  4  01005  Barbour  County,    AL   

解决方案 6:

如果您不想创建新的数据框,或者您的数据框包含的列多于您想要拆分的列,您可以:

df["flips"], df["row_name"] = zip(*df["row"].str.split().tolist())
del df["row"]  

解决方案 7:

用于df.assign创建一个新的 df。请参阅https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.assign.html

split = df_selected['name'].str.split(',', 1, expand=True)
df_split = df_selected.assign(first_name=split[0], last_name=split[1])
df_split.drop('name', 1, inplace=True)

或者以方法链形式:

df_split = (df_selected
            .assign(list_col=lambda df: df['name'].str.split(',', 1, expand=False),
                    first_name=lambda df: df.list_col.str[0],
                    last_name=lambda df: df.list_col.str[1])
            .drop(columns=['list_col']))

解决方案 8:

如果您想根据分隔符将字符串拆分为两列以上,则可以省略“最大拆分”参数。

您可以使用:

df['column_name'].str.split('/', expand=True)

这将自动创建与任何初始字符串中包含的最大字段数一样多的列。

解决方案 9:

很惊讶我还没看过这个。如果你只需要两部,我强烈推荐。。。

Series.str.partition

partition对分隔符执行一次拆分,并且通常性能很好。

df['row'].str.partition(' ')[[0, 2]]

       0                   2
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

如果需要重命名行,

df['row'].str.partition(' ')[[0, 2]].rename({0: 'fips', 2: 'row'}, axis=1)

    fips                 row
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

如果您需要将其重新加入到原始内容中,请使用joinconcat

df.join(df['row'].str.partition(' ')[[0, 2]])
pd.concat([df, df['row'].str.partition(' ')[[0, 2]]], axis=1)

                        row      0                   2
0       00000 UNITED STATES  00000       UNITED STATES
1             01000 ALABAMA  01000             ALABAMA
2  01001 Autauga County, AL  01001  Autauga County, AL
3  01003 Baldwin County, AL  01003  Baldwin County, AL
4  01005 Barbour County, AL  01005  Barbour County, AL

解决方案 10:

我发现没有人使用过切片方法,因此我在这里提出我的意见。

df["<col_name>"].str.slice(stop=5)
df["<col_name>"].str.slice(start=6)

此方法将创建两个新列。

解决方案 11:

我更喜欢导出对应的 pandas series(也就是我需要的列),使用apply函数将列内容拆分成多个 series,再将生成的列join到现有的 DataFrame 中。当然,源列应该被移除。

例如

 col1 = df["<col_name>"].apply(<function>)
 col2 = ...
 df = df.join(col1.to_frame(name="<name1>"))
 df = df.join(col2.toframe(name="<name2>"))
 df = df.drop(["<col_name>"], axis=1)

拆分两个单词的字符串函数应该是这样的:

lambda x: x.split(" ")[0] # for the first element
lambda x: x.split(" ")[-1] # for the last element

解决方案 12:

FutureWarning:在 pandas 的未来版本中,StringMethods.split 的所有参数(参数“pat”除外)都将是关键字专用的。

只是对第一个答案的一个小更新。

如果您遇到上面的警告消息(我目前使用的是pd.__version__= 1.5.3),在未来的版本中会变成错误,您可以通过将参数名称添加到参数中来避免它。因此,LeoRochael 发布的“最简单的解决方案”是:

# Will raise a warning or error
df[['A', 'B']] = df['AB'].str.split(' ', 1, expand=True)

应为:

# For newer pandas versions
df[['A', 'B']] = df['AB'].str.split(' ', n=1, expand=True)

此处发布的其他示例也需要参数的名称。

# For instance, if you want to split and remove the splitted columns
df[['A','B']] = df.pop('AB').str.split(n=1, expand=True)

我希望这能有所帮助。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用