Pandas Column 使用 Conditional 拆分一行并创建一个单独的 Column

Pandas Column Split a row with Conditional and create a separate Column

提问人:Stan 提问时间:10/15/2023 更新时间:10/16/2023 访问量:86

问:

似乎这个问题并不难,但不知何故我无法让它工作。我的问题如下。我有一个数据帧,如下所示:

       dfin 

           A      B     C
           a      1     198q24
           a      2     128q6
           a      6     1456
           b      7     67q22
           b      1     56
           c      3     451q2
           d      11    1q789

所以现在我想做的是如下,每当脚本遇到“q”时,它都会拆分值并创建一个单独的列,其值从“q”开始。“q”之前的部分将保留在原始部分(或者可以装箱一个新列)。所以我想要的输出应该如下:

        dfout 

           A      B     C        D
           a      1     198     q24
           a      2     128     q6
           a      6     1456
           b      7     67      q22
           b      1     56
           c      3     451     q2
           d      11    1       q789

所以我到目前为止尝试的如下:

       dfout = dfin.replace('\q\d*', '', regex=True)

它创建了一个没有 q 的列,但我无法创建 D 列并且无法按预期工作。

任何帮助/想法都会有所帮助并受到赞赏。

Python Pandas 正则表达式 group-by split

评论


答:

1赞 J_H 10/15/2023 #1
import pandas as pd


def get_input() -> pd.DataFrame:
    csv_text = """
         a      1     198q24
         a      2     128q6
         a      6     1456
         b      7     67q22
         b      1     56
         c      3     451q2
         d      11    1q789
         """.strip()
    return pd.DataFrame(map(str.split, csv_text.splitlines()), columns=["a", "b", "c"])


def split_on_q(df_in: pd.DataFrame) -> pd.DataFrame:
    df = df_in.c.str.split("q", expand=True)
    df_out = df_in.copy()
    df_out["c"] = df[0]
    df_out["d"] = _prepend_q(df[1])
    return df_out


def _prepend_q(series: pd.Series) -> pd.Series:
    return series.apply(lambda s: None if s is None else f"q{s}")


if __name__ == "__main__":
    print(split_on_q(get_input()))

输出:

   a   b     c     d
0  a   1   198   q24
1  a   2   128    q6
2  a   6  1456  None
3  b   7    67   q22
4  b   1    56  None
5  c   3   451    q2
6  d  11     1  q789
1赞 Suraj Shourie 10/15/2023 #2

有多种方法可以做到这一点,但一种方法是在拆分“q”上的列后使用:pd.concat

# temp dataframe
df2 = pd.DataFrame(df['C'].str.split('q').to_list(), columns=['C','D'])
# append to original 
df = pd.concat([df.drop(columns=['C']), df2], axis=1)
print(df)

打印:

   A   B     C     D
0  a   1   198    24
1  a   2   128     6
2  a   6  1456  None
3  b   7    67    22
4  b   1    56  None
5  c   3   451     2
6  d  11     1   789

评论

0赞 user19077881 10/16/2023
根据 OP 预期输出,列 'D' 在数字前应有 q。此外,应为空字符串,而不是 。None
1赞 Panda Kim 10/15/2023 #3

法典

str.extract

df.assign(D=df['C'].str.extract(r'(q\d*)'))

输出:

    A   B   C       D
0   a   1   198q24  q24
1   a   2   128q6   q6
2   a   6   1456    NaN
3   b   7   67q22   q22
4   b   1   56      NaN
5   c   3   451q2   q2
6   d   11  1q789   q789

我意识到我忽略了将 C 列从 @user19077881 更改的必要性。然后使用以下代码

df[['C', 'D']] = df['C'].str.extract(r'(\d+)(q\d+)*')

输出:

    A   B   C       D
0   a   1   198     q24
1   a   2   128     q6
2   a   6   1456    NaN
3   b   7   67      q22
4   b   1   56      NaN
5   c   3   451     q2
6   d   11  1       q789

如果不想就地到原始 DF,请使用以下代码:

df[['A', 'B']].join(df['C'].str.extract(r'(?P<C>\d+)(?P<D>q\d+)*'))

示例代码

import pandas as pd
data1 = {'A': ['a', 'a', 'a', 'b', 'b', 'c', 'd'], 
         'B': [1, 2, 6, 7, 1, 3, 11], 
         'C': ['198q24', '128q6', '1456', '67q22', '56', '451q2', '1q789']}
df = pd.DataFrame(data1)

评论

0赞 user19077881 10/16/2023
为了产生OP的预期输出,还需要将其应用于str.extract(r'(\d+)q?')df['C']
0赞 Panda Kim 10/16/2023
@user19077881 您的建议与提问者期望的输出完全不同。最好在提出建议之前运行代码。
0赞 user19077881 10/16/2023
我要指出的是,您保留了原始的列 C,而 OP 只想要 q 之前的数字
0赞 Panda Kim 10/16/2023
@user19077881我误解了你说的话。我道歉。我已经更正了我的答案。