[英]How to split a dataframe string column into two columns?
我有一個包含一列(字符串)的數據框,我想將其拆分為兩列(字符串),一列 header 作為“ fips'
,另一列作為'row'
我的 dataframe 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
對於簡單的情況:
最簡單的解決方案是:
df[['A', 'B']] = df['AB'].str.split(' ', 1, expand=True)
如果您的字符串具有不均勻的拆分數量並且您希望None
替換缺失值,則必須使用expand=True
。
請注意,在任何一種情況下,都不需要.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()
的前兩個參數是做什么的,我推薦使用該方法的純 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
可能有更好的方法,但這是一種方法:
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
您可以使用正則表達式模式非常巧妙地提取不同的部分:
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 ]*$)
*
) 的大寫字母或空格 ( [AZ ]
) 並在字符串 ( $
) 的結尾之前命名此"state"
,或者
(?P<county>.*?), (?P<state_code>[A-Z]{2}$))
.*
)然后$
) 之前的兩位數state_code
。 在示例中:
請注意,前兩行命中“州”(將 NaN 留在縣和 state_code 列中),而最后三行命中縣 state_code(將 NaN 留在州列中)。
df[['fips', 'row']] = df['row'].str.split(' ', n=1, expand=True)
您可以使用str.split
by whitespace(默認分隔符)和參數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
然后解決方案是通過join
追加新的DataFrame
:
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
如果您不想創建新的數據框,或者您的數據框的列多於您要拆分的列,您可以:
df["flips"], df["row_name"] = zip(*df["row"].str.split().tolist())
del df["row"]
如果您想根據分隔符將字符串拆分為多於兩列,您可以省略“最大拆分”參數。
您可以使用:
df['column_name'].str.split('/', expand=True)
這將自動創建與任何初始字符串中包含的最大字段數一樣多的列。
很驚訝我還沒有看到這個。 如果你只需要兩個拆分,我強烈推薦。 . .
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
如果您需要將其加入到原始狀態,請使用join
或concat
:
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.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']))
我更喜歡導出對應的pandas系列(即我需要的列),使用apply函數將列內容拆分成多個系列,然后將生成的列加入到已有的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
我看到沒有人使用切片方法,所以我把我的 2 美分放在這里。
df["<col_name>"].str.slice(stop=5)
df["<col_name>"].str.slice(start=6)
此方法將創建兩個新列。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.