简短版本:
对于简单的情况:
最简单的解决方案是:
df[['A', 'B']] = df['AB'].str.split(' ', n=1, expand=True)
如果您的字符串拆分数量不均匀,并且希望使用expand=True
将None
替换为缺失值,那么您必须使用expand=True
。
无论哪种情况,都不需要使用.tolist()
方法。也不需要使用zip()
。
详细说明:
Andy Hayden的解决方案非常出色地展示了str.extract()
方法的强大之处。
但是对于已知分隔符的简单拆分(例如,通过破折号拆分或通过空格拆分),.str.split()
方法就足够了1。它适用于字符串的列(Series),并返回一个列表的列(Series):
>>> 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()
的前两个参数是什么意思,我建议你查看
纯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('-', 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
read_table()
或read_fwf()
来以所需格式加载数据。 - zach