如何将一列分为两列?


196

我有一个带有一列的数据框,我想将其分为两列,其中一列标题为' 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

3
您如何将数据加载到熊猫中?您也许可以使用read_table()read_fwf()
zach 2013年

Answers:


135

也许有更好的方法,但这是一种方法:

                            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 = ['flips','row'])
   flips                 row
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

6
请注意,.tolist()会删除您拥有的所有索引,因此新的Dataframe将从0重新索引(在您的特定情况下这无关紧要)。
Crashthatch 2013年

10
@Crashthatch-然后您可以再次添加就可以了index = df.index

如果一个单元格不能分裂怎么办?
Nisba

@Nisba:如果无法拆分任何单元格(例如,在这种情况下字符串不包含任何空格),它将仍然有效,但是拆分的一部分将为空。如果您在列中混合使用至少有一个包含任何数字类型的单元格的类型,则会发生其他情况。然后该split方法返回NaN,该tolist方法将按原样返回此值(NaN),这将导致ValueError(要解决此问题,可以在拆分之前将其转换为字符串类型)。我建议您自己尝试一下,这是最好的学习方法:-)
Nerxis

@techkuz:您确定您df具有row列标题吗?您可能会认为这是某种DataFrame属性,但很明显,这是列的名称。如何创建和定义列标题取决于您,因此如果您使用其他标题(例如df.my_column_name.split(...)),请使用它。
Nerxis

386

TL; DR版本:

对于以下简单情况:

  • 我有一个带有定界符的文本列,我想要两列

最简单的解决方案是:

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

或者,您可以使用以下方法自动为拆分的每个条目创建一个带有一列的DataFrame:

df['AB'].str.split(' ', 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:如果不确定.str.split()do 的前两个参数是什么,我建议使用该方法纯Python版本的文档。

但是你如何去做:

  • 包含两个元素的列表的列

至:

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

好吧,我们需要仔细查看.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('-', 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('-', 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('-', 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

df ['A'],df ['B'] = df ['AB']。str.split('',1).str split(''',1)中的'1'是什么意思?
Hariprasad

@Hariprasad,这是分割的最大数量。我已为该.split()方法的Python版本文档添加了一个链接,该链接比Pandas文档更好地解释了前两个参数。
LeoRochael

5
pandas 1.0.0报告“未来警告:在将来的版本中,不赞成在字符上进行列式迭代。”
弗兰克

1
这在Python 1.0.1下有效。df.join(df['AB'].str.split('-', 1, expand=True).rename(columns={0:'A', 1:'B'}))
Martien Lubberink

59

您可以使用正则表达式模式整齐地提取不同部分:

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字符串($)末尾的两位数字。

在示例中:
请注意,前两行命中“州”(将NaN保留在county和state_code列中),而后三行命中县(即state_code)(将NaN保留在state列中)。


这绝对是最好的解决方案,但是对于使用非常广泛的正则表达式的某些人来说可能有点不堪重负。为什么不将其作为第二部分,而仅将第一部分和第几列包含在第一部分呢?
小鲍比表

2
@josh是个好主意,尽管正则表达式的各个部分“很容易理解”,但是长的正则表达式会很快变得复杂。我为以后的读者增加了一些解释!(我还必须更新指向说明(?P<label>...)语法的文档的链接!我不知道为什么要选择更复杂的正则表达式,显然简单的正则表达式可以正常工作
Andy Hayden

1
看起来更友好。我很高兴您这样做,因为它让我查看了文档以了解<group_name>。现在,我知道它使我的代码非常简洁。
小鲍比桌


22

如果您不想创建新的数据框,或者您的数据框具有比仅要拆分的列更多的列,则可以:

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

1
我收到一个zip argument #1 must support iteration错误,python 2.7
艾伦·鲁恩

20

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

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

然后将解决方案添加到新DataFramejoin

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   

8

如果要基于定界符将字符串分为两列以上,则可以省略“ maximum splits”参数。
您可以使用:

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

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


6

感到惊讶的是我还没有看到这个。如果您只需要两个分割,我强烈建议您。。。

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

0

我更喜欢导出相应的熊猫系列(即我需要的列),使用apply函数将列内容分为多个系列,然后加入生成的列到现有的数据帧。当然,应删除源列。

例如

 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

0

我看到没有人使用过切片法,所以在这里我放了2美分。

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

此方法将创建两个新列。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.