【问题标题】:Pandaic approach to iterating over a dataframe遍历数据框的 Pandaic 方法
【发布时间】:2018-02-21 23:51:37
【问题描述】:

我正在使用 Excel 输入制作测试团队报告;使用 pandas 收集、过滤、处理数据。

我制作了以下代码来制作产品测试用例封面表以供以后使用/轻松搜索。第三列是测试用例的类型。我在一个 excel 中有多个测试用例,所以我需要遍历所有单元格并拆分测试以制作成对的产品 - 测试用例。

因为我对 pandas 不太熟悉,而且我在其他地方也没有找到更好的方法,所以我想问一下是否有更多的 pythonic 方式或更简单的 pandas 方式来做同样的事情和更高效。

带有示例数据的代码(\n 是 excel 单元格内的换行符):

df = pd.DataFrame({"prod":["TS001","TS002"], 
                   "activate":["001_002\n001_004", "003_008\n024_080"],
                   "deactivate":["004_005\n006_008", "001_008"]})
df = df.set_index("prod")

list_of_tuples = []

for i, row in df.iterrows():
    for cell in row.iteritems():
        for test in cell[-1].splitlines():
            list_of_tuples.append((i, test, cell[0]))  # [(product, test, category)..]

return_df = pd.DataFrame(list_of_tuples, columns=('prod', 'testcase', 'category'))

制作:

    prod testcase    category
0  TS001  001_002    activate
1  TS001  001_004    activate
2  TS001  004_005  deactivate
3  TS001  006_008  deactivate
4  TS002  003_008    activate
5  TS002  024_080    activate
6  TS002  001_008  deactivate

感谢您的任何建议。

【问题讨论】:

    标签: python pandas dataframe iteration


    【解决方案1】:

    理解

    pd.DataFrame(
        [(p, t, c) for (p, c), r in df.stack().items() for t in r.split()],
        columns=['prod', 'testcase', 'category']
    )
    
        prod testcase    category
    0  TS001  001_002    activate
    1  TS001  001_004    activate
    2  TS001  004_005  deactivate
    3  TS001  006_008  deactivate
    4  TS002  003_008    activate
    5  TS002  024_080    activate
    6  TS002  001_008  deactivate
    

    说明

    df.stack()
    
    prod             
    TS001  activate      001_002\n001_004
           deactivate    004_005\n006_008
    TS002  activate      003_008\n024_080
           deactivate             001_008
    dtype: object
    

    当迭代df.stack().items() 时,我们得到以索引值为第一个元素、值为第二个元素的元组。因为我们堆叠,索引值本身就是一个元组。所以第一对看起来像:

    (('TS001', 'activate'), '001_002\n001_004')
    

    通过对'001_002\n001_004'.split() 的后续迭代并重新排列解包的元素,我们得到

    [(p, t, c) for (p, c), r in df.stack().items() for t in r.split()]
    
    [('TS001', '001_002', 'activate'),
     ('TS001', '001_004', 'activate'),
     ('TS001', '004_005', 'deactivate'),
     ('TS001', '006_008', 'deactivate'),
     ('TS002', '003_008', 'activate'),
     ('TS002', '024_080', 'activate'),
     ('TS002', '001_008', 'deactivate')]
    

    然后我将其包装在一个 pd.DataFrame 构造函数中,并在其中命名列。

    【讨论】:

    • 我正在观察这一点,你对复杂理解的后期迷恋;)和一个简洁的答案!
    • 我倾向于一次滥用一个维度。我经历了query 阶段、pd.factorize 阶段、stack 阶段。即使是pokemon 阶段....等等,这无关紧要!
    • 先生,如果可以的话,请添加基准。我认为,这比其他方法效率高很多,这个答案值得关注。
    • 这看起来确实不错。谢谢你的解释。对其他人的一个澄清,这个答案紧随其后: df = df.set_index('prod')
    • 这样干净整洁。
    【解决方案2】:

    用途:

    • set_index 喜欢你的解决方案
    • apply 用于使用 DataFramesplitexpand=True 的 lambda 函数处理多个列,并通过 stack 进行整形
    • unstackMultiindex 的列
    • reset_index 首先用于删除级别,然后将Multiindex 用于列
    • 重命名列
    • reindex_axis 用于更改列的顺序

    df = (df.set_index('prod')
            .apply(lambda x: x.str.split('\n', expand=True).unstack())
            .stack()
            .reset_index(level=0, drop=True)
            .reset_index(name='testcase')
            .rename(columns={'level_1':'category'})
            .reindex_axis(['prod','testcase','category'], axis=1))
    print (df)
        prod testcase    category
    0  TS001  001_002    activate
    1  TS001  004_005  deactivate
    2  TS002  003_008    activate
    3  TS002  001_008  deactivate
    4  TS001  001_004    activate
    5  TS001  006_008  deactivate
    6  TS002  024_080    activate
    

    【讨论】:

    • 恐怕,如果有另一行 prod 等于 TS001TS002,这将不起作用?
    • 不确定,不要测试。我得走了,以后再说吧。
    • 感谢您的回答!真的行。我无法让应用/应用映射自己工作,所以我以 for 循环结束。
    • 我有一个改进,请稍等。
    • 是的,需要unstack而不是stack,然后它通常工作得很好。
    【解决方案3】:

    使用 df.applymapdf.meltdf.stack

    df = df.applymap(str.split).reset_index().melt('prod', \
                  ['activate', 'deactivate']).set_index(['prod', 'variable'])
    df = pd.DataFrame(df.value.tolist(), index=df.index)\
                             .stack().reset_index().drop('level_2', 1) 
    df.columns = ['prod', 'category', 'testcase']
    
    df
        prod    category testcase
    0  TS001    activate  001_002
    1  TS001    activate  001_004
    2  TS002    activate  003_008
    3  TS002    activate  024_080
    4  TS001  deactivate  004_005
    5  TS001  deactivate  006_008
    6  TS002  deactivate  001_008
    

    【讨论】:

    【解决方案4】:

    这是一种方法,可能还有更好的方法。检查piRSquared's - 应该是这里最有效的。

    In [2807]: (df.set_index('prod')
                  .applymap(lambda x: x.split('\n'))
                  .stack()
                  .apply(pd.Series)
                  .stack()
                  .reset_index(name='testcase')
                  .rename(columns={'level_1': 'category'})
                  .drop('level_2', 1))
    Out[2807]:
        prod    category testcase
    0  TS001    activate  001_002
    1  TS001    activate  001_004
    2  TS001  deactivate  004_005
    3  TS001  deactivate  006_008
    4  TS002    activate  003_008
    5  TS002    activate  024_080
    6  TS002  deactivate  001_008
    

    详情

    In [2809]: df
    Out[2809]:
               activate        deactivate   prod
    0  001_002\n001_004  004_005\n006_008  TS001
    1  003_008\n024_080           001_008  TS002
    

    【讨论】:

    • 感谢您的快速回答!我正在研究 apply / applymap 但无法完成。
    猜你喜欢
    • 2017-05-20
    • 2018-01-28
    • 2022-01-12
    • 2021-02-17
    • 2013-04-12
    • 2023-02-08
    • 2020-11-11
    相关资源
    最近更新 更多