如何将一列分成两列?
我有一列的数据框,我想分成两列,其中一列的标题为' 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
可能有更好的办法,但这是一个办法:
In [34]: import pandas as pd In [35]: df Out[35]: row 0 00000 UNITED STATES 1 01000 ALABAMA 2 01001 Autauga County, AL 3 01003 Baldwin County, AL 4 01005 Barbour County, AL In [36]: df = pd.DataFrame(df.row.str.split(' ',1).tolist(), columns = ['flips','row']) In [37]: df Out[37]: flips row 0 00000 UNITED STATES 1 01000 ALABAMA 2 01001 Autauga County, AL 3 01003 Baldwin County, AL 4 01005 Barbour County, AL
TL; DR版本:
对于简单的情况:
- 我有一个分隔符的文本列,我想要两列
最简单的解决scheme是:
df['A'], df['B'] = df['AB'].str.split(' ', 1).str
或者,您可以创build一个DataFrame自动创build与一列的每个条目自动与:
df['AB'].str.split(' ', 1, expand=True)
请注意,在这两种情况下, .tolist()
方法都是不必要的。 zip()
都不是。
详细:
Andy Hayden的解决scheme在演示str.extract()
方法的function方面非常出色。
但是对于一个已知分隔符的简单分割(比如,用破折号分割或者用空格分割) .str.split()
方法就足够了1 。 它在string的列(系列)上运行,并返回列表(系列):
>>> 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
属性。
这是一个神奇的对象,用于收集将列中每个元素作为string对待的方法,然后尽可能高效地在每个元素中应用相应的方法:
>>> 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 UL 0 A a 1 B b 2 C c
但它也有一个“索引”接口,通过它的索引获取string的每个元素:
>>> 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
索引接口并不关心它索引的每个元素是否是一个string,只要它可以被索引,那么:
>>> 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元组解开iterables来做一件简单的事
>>> df['A'], df['B'] = df['AB'].str.split('-', 1).str >>> df AB AB_split AB 0 A1-B1 [A1, B1] A1 B1 1 A2-B2 [A2, B2] A2 B2
当然,获取DataFrame分割一列string非常有用, .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 AB 0 A1-B1 A1 B1 1 A2-B2 A2 B2
你可以使用正则expression式很好地提取不同的部分:
In [11]: df.row.str.extract('(?P<fips>\d{5})((?P<state>[AZ ]*$)|(?P<county>.*?), (?P<state_code>[AZ]{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]
解释这个有点长的正则expression式:
(?P<fips>\d{5})
- 匹配五位数字(
\d
)并将其命名为"fips"
。
下一部分:
((?P<state>[AZ ]*$)|(?P<county>.*?), (?P<state_code>[AZ]{2}$))
是否( |
)两件事之一:
(?P<state>[AZ ]*$)
- 匹配任何数字(
*
)的大写字母或空格([AZ ]
),并在string($
)结束之前将这个"state"
要么
(?P<county>.*?), (?P<state_code>[AZ]{2}$))
- 匹配其他任何(
.*
)然后 - 一个逗号和一个空格
- 匹配string(
$
)结束之前的两位数字state_code
。
在这个例子中:
请注意,前两行命中“状态”(在县和state_code列中留下NaN),而最后三个命中县state_code(在状态列中留下NaN)。
如果您不想创build新的数据框,或者您的数据框的列数多于要分割的数据列数,则可以:
df["flips"], df["row_name"] = zip(*df["row"].str.split().tolist()) del df["row"]