Python 如何将dataframe字符串列拆分为两列?

Python 如何将dataframe字符串列拆分为两列?,python,dataframe,pandas,Python,Dataframe,Pandas,我有一个包含一列(字符串)的数据框,我想将其拆分为两列(字符串),其中一列标题为“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[:]来实现拆分行单

我有一个包含一列(字符串)的数据框,我想将其拆分为两列(字符串),其中一列标题为“
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

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

                            row
    0       00000 UNITED STATES
    1             01000 ALABAMA
    2  01001 Autauga County, AL
    3  01003 Baldwin County, AL
    4  01005 Barbour County, AL
您可以使用正则表达式模式将不同的部分整齐地显示出来:

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<state>[A-Z ]*$)
  • 匹配任何其他内容(
    *
    ),然后
  • 一个逗号和一个空格
  • 匹配字符串(
    $
    )结尾前的两位
    状态\u code
在示例中:

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

如果您不想创建新的数据帧,或者如果您的数据帧的列数超过了要拆分的列数,则可以:

df["flips"], df["row_name"] = zip(*df["row"].str.split().tolist())
del df["row"]  
TL;DR版本: 对于以下简单情况:

  • 我有一个带分隔符的文本列,我想要两列
最简单的解决方案是:

df[['A', 'B']] = df['AB'].str.split(' ', 1, expand=True)
如果字符串的拆分数目不一致,并且希望
None
替换缺少的值,则必须使用
expand=True

请注意,在这两种情况下,
.tolist()
方法都不是必需的。两者都不是
zip()

详细内容: 在证明该方法的威力方面最为出色

但是对于在已知分隔符上进行的简单拆分(例如,用破折号拆分或用空格拆分),方法是enough1。它对字符串列(系列)进行操作,并返回列表列(系列):

>>> 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()
的前两个参数的作用, 我推荐这本书的文档

但你如何从:

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

  • 两列,每列包含列表的各个元素
好的,我们需要仔细查看列的
.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
然后,只需利用iterables的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
当然,从拆分字符串列中获取数据帧非常有用,
.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['column_name'].str.split('/', expand=True)
这将自动创建与任何初始字符串中包含的最大字段数相同的列

您可以通过空格(默认分隔符)和参数
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
如需修改,请使用

什么是一样的:

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列
数据帧
,而不仅仅是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

使用“删除原始列”(如果还有其他列):


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

e、 g


很惊讶我还没看到这个。如果您只需要两次分割,我强烈推荐

分区
在分隔符上执行一次拆分,通常性能相当好

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
如果需要将此连接回原始连接,请使用
join
concat

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


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

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

此方法将创建两个新列。

使用
df.assign
创建新的df。看

split=df_selected['name'].str.split(',',1,expand=True)
df_split=df_selected.assign(名字=split[0],姓氏=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']))

您是如何将数据加载到pandas中的?您可以使用
read_table()
read_fwf()
以所需格式读取数据。根据列是字符串、列表还是其他格式,以及何种格式,“如何拆分列”有不同的答案(例如,“格式化字符串”类似于地址,您可能需要使用正则表达式。这里有一个固定宽度格式的字符串列(“ZZZZZ placename…”),因此我们知道zipcode是字符0:4和
#remove n=1 for split by all whitespaces
df[['a','b']] = df['row'].str.split(expand=True)
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
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   
 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
df[['fips', 'row']] = df['row'].str.split(' ', n=1, expand=True)
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
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
df["<col_name>"].str.slice(stop=5)
df["<col_name>"].str.slice(start=6)
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']))