根据 pandas 中另一列的值创建新列
Creating new columns based on value from another column in pandas
我有这个 pandas 数据框,其列 "Code" 包含顺序分层代码。我的目标是使用每个层次级别代码及其名称创建新列,如下所示:
原始数据:
Code Name
0 A USA
1 AM Massachusetts
2 AMB Boston
3 AMS Springfield
4 D Germany
5 DB Brandenburg
6 DBB Berlin
7 DBD Dresden
我的目标:
Code Name Level1 Level1Name Level2 Level2Name Level3 Level3Name
0 A USA A USA AM Massachusetts AMB Boston
1 AM Massachusetts A USA AM Massachusetts AMB Boston
2 AMB Boston A USA AM Massachusetts AMB Boston
3 AMS Springfield A USA AM Massachusetts AMS Springfiled
4 D Germany D Germany DB Brandenburg DBB Berlin
5 DB Brandenburg D Germany DB Brandenburg DBB Berlin
6 DBB Berlin D Germany DB Brandenburg DBB Berlin
7 DBD Dresden D Germany DB Brandenburg DBD Dresden
我的代码:
import pandas as pd
df = pd.read_excel(r'/Users/BoBoMann/Desktop/Sequence.xlsx')
df['Length']=test.Code.str.len() ## create a column with length of each cell in Code
df['Level1']=test.Code.str[:1] ## create the first level using string indexing
df['Level1Name'] = df[df['Length']==1]['Name']
df.head() ## This yields:
Code Name Length Level1 Level1Name
0 A USA 1 A USA
1 AM Massachusetts 2 A NaN
2 AMB Boston 3 A NaN
3 AMS Springfield 3 A NaN
4 D Germany 1 D Germany
5 DB Brandenburg 2 D NaN
6 DBB Berlin 3 D NaN
7 DBD Dresden 3 D NaN
对于我目前的方法,如何在 Level1Name 列中将这些 NaN 分别变成 USA 和 Germany?
一般来说,有没有更好的方法来实现我的目标,即为每个分层创建列并将它们与另一列中各自的名称相匹配?
IIUC,让我们使用这个代码:
df['Codes'] = [[*i] for i in df['Code']]
df_level = df['Code'].str.extractall('(.)')[0].unstack('match').bfill().cumsum(axis=1)
s_map = df.explode('Codes').drop_duplicates('Code', keep='last').set_index('Code')['Name']
df_level.columns = [f'Level{i+1}' for i in df_level.columns]
df_level_names = pd.concat([df_level[i].map(s_map) for i in df_level.columns],
axis=1,
keys=df_level.columns+'Name')
df_out = df.join([df_level, df_level_names]).drop('Codes', axis=1)
df_out
输出:
Code Name Level1 Level2 Level3 Level1Name Level2Name Level3Name
0 A USA A AM AMB USA Massachusetts Boston
1 AM Massachusetts A AM AMB USA Massachusetts Boston
2 AMB Boston A AM AMB USA Massachusetts Boston
3 AMS Springfield A AM AMS USA Massachusetts Springfield
4 D Germany D DB DBB Germany Brandenburg Berlin
5 DB Brandenburg D DB DBB Germany Brandenburg Berlin
6 DBB Berlin D DB DBB Germany Brandenburg Berlin
7 DBD Dresden D DB DBD Germany Brandenburg Dresden
解释:
- 将字符串解压缩到创建 'Codes' 列的字符列表中
- 使用
extractall
和正则表达式 .
创建 'LevelX' 列以获得
单个字符,然后 bfill
上面的 NaN 和 cumsum
沿行到
创建 'LevelX' 列
- 通过在 'Codes' 上调用
explode
创建一个 pd.Series 与 map
一起使用
在上方创建列并 drop_duplicates
保留最后一个值
'Code' 然后在 'Codes' 上 set_index
并保留 'Name' 列
创建 's_map'.
- 重命名名称 df_level 列以获取 Level1 而不是 Level0。
- 使用
pd.concat
和 map
df_level 列的列表理解
df_level_names 使用 s_map。另外,使用 keys
参数重命名
新列并附加 'Name'
- 使用
join
连接 df 与 df_levels 和 df_level_names,然后 drop
'Codes' 列,创建所需的输出。
我有这个 pandas 数据框,其列 "Code" 包含顺序分层代码。我的目标是使用每个层次级别代码及其名称创建新列,如下所示:
原始数据:
Code Name
0 A USA
1 AM Massachusetts
2 AMB Boston
3 AMS Springfield
4 D Germany
5 DB Brandenburg
6 DBB Berlin
7 DBD Dresden
我的目标:
Code Name Level1 Level1Name Level2 Level2Name Level3 Level3Name
0 A USA A USA AM Massachusetts AMB Boston
1 AM Massachusetts A USA AM Massachusetts AMB Boston
2 AMB Boston A USA AM Massachusetts AMB Boston
3 AMS Springfield A USA AM Massachusetts AMS Springfiled
4 D Germany D Germany DB Brandenburg DBB Berlin
5 DB Brandenburg D Germany DB Brandenburg DBB Berlin
6 DBB Berlin D Germany DB Brandenburg DBB Berlin
7 DBD Dresden D Germany DB Brandenburg DBD Dresden
我的代码:
import pandas as pd
df = pd.read_excel(r'/Users/BoBoMann/Desktop/Sequence.xlsx')
df['Length']=test.Code.str.len() ## create a column with length of each cell in Code
df['Level1']=test.Code.str[:1] ## create the first level using string indexing
df['Level1Name'] = df[df['Length']==1]['Name']
df.head() ## This yields:
Code Name Length Level1 Level1Name
0 A USA 1 A USA
1 AM Massachusetts 2 A NaN
2 AMB Boston 3 A NaN
3 AMS Springfield 3 A NaN
4 D Germany 1 D Germany
5 DB Brandenburg 2 D NaN
6 DBB Berlin 3 D NaN
7 DBD Dresden 3 D NaN
对于我目前的方法,如何在 Level1Name 列中将这些 NaN 分别变成 USA 和 Germany?
一般来说,有没有更好的方法来实现我的目标,即为每个分层创建列并将它们与另一列中各自的名称相匹配?
IIUC,让我们使用这个代码:
df['Codes'] = [[*i] for i in df['Code']]
df_level = df['Code'].str.extractall('(.)')[0].unstack('match').bfill().cumsum(axis=1)
s_map = df.explode('Codes').drop_duplicates('Code', keep='last').set_index('Code')['Name']
df_level.columns = [f'Level{i+1}' for i in df_level.columns]
df_level_names = pd.concat([df_level[i].map(s_map) for i in df_level.columns],
axis=1,
keys=df_level.columns+'Name')
df_out = df.join([df_level, df_level_names]).drop('Codes', axis=1)
df_out
输出:
Code Name Level1 Level2 Level3 Level1Name Level2Name Level3Name
0 A USA A AM AMB USA Massachusetts Boston
1 AM Massachusetts A AM AMB USA Massachusetts Boston
2 AMB Boston A AM AMB USA Massachusetts Boston
3 AMS Springfield A AM AMS USA Massachusetts Springfield
4 D Germany D DB DBB Germany Brandenburg Berlin
5 DB Brandenburg D DB DBB Germany Brandenburg Berlin
6 DBB Berlin D DB DBB Germany Brandenburg Berlin
7 DBD Dresden D DB DBD Germany Brandenburg Dresden
解释:
- 将字符串解压缩到创建 'Codes' 列的字符列表中
- 使用
extractall
和正则表达式.
创建 'LevelX' 列以获得 单个字符,然后bfill
上面的 NaN 和cumsum
沿行到 创建 'LevelX' 列 - 通过在 'Codes' 上调用
explode
创建一个 pd.Series 与map
一起使用 在上方创建列并drop_duplicates
保留最后一个值 'Code' 然后在 'Codes' 上set_index
并保留 'Name' 列 创建 's_map'. - 重命名名称 df_level 列以获取 Level1 而不是 Level0。
- 使用
pd.concat
和map
df_level 列的列表理解 df_level_names 使用 s_map。另外,使用keys
参数重命名 新列并附加 'Name' - 使用
join
连接 df 与 df_levels 和 df_level_names,然后drop
'Codes' 列,创建所需的输出。