Pandas: 旧列生成新列

Pandas: Generate new columns by old one

我有一个数据框,其中一列来自国际象棋 FEN notations,我想拆分这一列,其格式为

2kr2nr/pp5p/3bpppP/1b1p4/8/1BB1P3/PP3PP1/R3K2R

分为 a1 到 h8 的 64 列,其中包含其中的字母,或者 - 如果它是空的。

功能稍微复杂一点,应该不是题主的问题,但是我问自己的是:

从 pandas 数据帧中的一列生成 64 列的最佳方法是什么?

我知道应用函数之类的东西,它可以 运行 一个函数,但我只在一列中看到过。 有没有一种聪明的方法可以一次对所有 64 列执行此操作?


对于那些想知道我所做的确切事情的人:

FEN 由八个由 / 分隔的子字符串组成,它们是第 8 行到第 1 行(是的,顺序相反)。 每个部分说明该行中的八个字段的外观。如果有一个数字,它表示有多少个空字段(从左开始),如果是一个字母,它表示后面是哪一块。

所以在我上面的例子中,a8和b8是空的(因为2),然后有一个“k”,“r”,e8和h8上还有两个空,后面是“n”和“r”。一行中出现 8 表示该行为空。

举个例子: 输入:

2kr2nr/pp5p/3bpppP/1b1p4/8/1BB1P3/PP3PP1/R3K2R

输出:

a8 -
b8 -
c8 k
d8 r
e8 -
f8 -
g8 n
h8 r
a7 p
b7 p
c7 -
d7 -
e7 -
f7 -
g7 -
h7 p
...
a1 R
b2 -
c1 -
d1 -
e1 K
f1 -
g1 -
h1 R

您可以使用自定义函数。例如:

def fen2list(s):
    from itertools import chain, product
    l = list(chain.from_iterable('-'*int(c)
                                 if c.isdigit() else c
                                 for c in s if c != '/'))
    
    cols = list(map(''.join, product('abcdefgh', '87654321')))
    
    return pd.Series(l, index=cols)

示例:

fen2list('2kr2nr/pp5p/3bpppP/1b1p4/8/1BB1P3/PP3PP1/R3K2R')

输出:

a8    -
a7    -
a6    k
a5    r
a4    -
     ..
h5    -
h4    K
h3    -
h2    -
h1    R

如果您的 DataFrame 包含一列 FEN 字符串,您可以将 apply 与您的自定义函数一起使用:

df['FEN'].apply(fen2list)

假设以下数据框:

import pandas as pd

# https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation#Examples
data = ['rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR',
        'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR',
        'rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR',
        'rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R']
df = pd.DataFrame({'FEN': data})
print(df)

# Output
                                                 FEN
0        rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
1      rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR
2    rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR
3  rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R

创建解码函数(改编自@TimRoberts

from itertools import product

cells = [f"{l}{n}" for n, l in product('87654321', 'ABCDEFGH')]

def decode_fen(fen):
    board = []
    for c in fen:
        if c == '/':
            continue
        elif c.isdigit():
            board.extend('-' * int(c))
        elif c.isalpha():
            board.append(c)
        else:
            board.append('-')
    return pd.Series(board, index=cells)

创建您的专栏:

fen = df['FEN'].apply(decode_fen)

df = df.join(fen)

输出:

>>> df
                                                 FEN A8 B8 C8 D8 E8 F8 G8 H8 A7 B7 C7 D7 E7 F7 G7 H7 A6 B6 C6 D6 E6 F6 G6 H6 A5 B5 C5 D5 E5 F5 G5 H5 A4 B4 C4 D4 E4 F4 G4 H4 A3 B3 C3 D3 E3 F3 G3 H3 A2 B2 C2 D2 E2 F2 G2 H2 A1 B1 C1 D1 E1 F1 G1 H1
0        rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR  r  n  b  q  k  b  n  r  p  p  p  p  p  p  p  p  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  P  P  P  P  P  P  P  P  R  N  B  Q  K  B  N  R
1      rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR  r  n  b  q  k  b  n  r  p  p  p  p  p  p  p  p  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  P  -  -  -  -  -  -  -  -  -  -  -  P  P  P  P  -  P  P  P  R  N  B  Q  K  B  N  R
2    rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR  r  n  b  q  k  b  n  r  p  p  -  p  p  p  p  p  -  -  -  -  -  -  -  -  -  -  p  -  -  -  -  -  -  -  -  -  P  -  -  -  -  -  -  -  -  -  -  -  P  P  P  P  -  P  P  P  R  N  B  Q  K  B  N  R
3  rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R  r  n  b  q  k  b  n  r  p  p  -  p  p  p  p  p  -  -  -  -  -  -  -  -  -  -  p  -  -  -  -  -  -  -  -  -  P  -  -  -  -  -  -  -  -  N  -  -  P  P  P  P  -  P  P  P  R  N  B  Q  K  B  -  R