【问题标题】:Append column in a dataframe with string values使用字符串值在数据框中追加列
【发布时间】:2019-03-10 17:19:44
【问题描述】:

我有一个案例,我试图以可理解的格式将计算出的百分比值附加到我的数据框中名为 df 的列中。当我说可理解的格式时,列中的输出应该类似于'40% Matched',如下例所示。

df = pd.DataFrame({ 'Col1':[['Phone', 'Watch', 'Pen', 'Pencil', 'Knife'],['apple','orange','mango','cherry','banana','kiwi','tomato','avocado']], 'Col2': [['Phone', 'Watch', 'Pen', 'Pencil', 'fork'],['orange','avocado','kiwi','mango','grape','lemon','tomato']]})

df['Matched Percent'] = 'No Match'

for index,(lst1,lst2) in enumerate(zip(df['Col1'],df['Col2'])):
   if(lst1 == lst2):
      print('100% Matched')
   else:
      c1 = Counter(lst1)
      c2 = Counter(lst2)
      matching = {k: c1[k]+c2[k] for k in c1.keys() if k in c2}
      text = '% Matched'
      if len(lst1) > len(lst2):
         out = round(len(matching)/len(lst1)*100)
         #df['Matched Percent'].append(out,'% Matched')
         print(out,'% Matched')
      else:
         out = round(len(matching)/len(lst2)*100)
         #df['Matched Percent'].append(out,'% Matched')
         print(out,'% Matched')

80 % Matched
62 % Matched

TypeError: cannot concatenate object of type "<class 'int'>"; only pd.Series, pd.DataFrame, and pd.Panel (deprecated) objs are valid

我不断收到 TypeError。我尝试了几种方法,但没有运气。如上所示,我能够以我想要的方式在屏幕上打印值。但是当我将它附加到我的数据框df 时,它失败了。感谢有关如何解决此问题的建议。

【问题讨论】:

    标签: python string python-3.x pandas typeerror


    【解决方案1】:

    您的逻辑似乎很冗长。您可以使用列表推导:

    zipper = zip(map(set, df['Col1']), map(set, df['Col2']))
    df['Matched Percent'] = [len(c1 & c2) / max(len(c1), len(c2)) for c1, c2 in zipper]
    
    print(df)
    
                                                    Col1  \
    0                 [Phone, Watch, Pen, Pencil, Knife]   
    1  [apple, orange, mango, cherry, banana, kiwi, t...   
    
                                                    Col2  Matched Percent  
    0                  [Phone, Watch, Pen, Pencil, fork]            0.800  
    1  [orange, avocado, kiwi, mango, grape, lemon, t...            0.625  
    

    请注意,使用 Pandas 优化此类计算的余地不大,Pandas 的设计目的不是用于保存串联列表。如果你需要“漂亮”的输出,你可以使用 Python 3.6+ 支持的 f-strings:

    print((df['Matched Percent']*100).map(lambda x: f'{x:.0f}% Matched'))
    
    0    80% Matched
    1    62% Matched
    Name: Matched Percent, dtype: object
    

    【讨论】:

    • 这很好用。我看到输出值看起来像小数。以百分比形式打印会很好。我试过这个,df['Matched Percent'] = [((len(c1 &amp; c2)/max(len(c1), len(c2)))*100) for c1, c2 in zipper]。但是你能做得更好吗?
    • 刚看到你的评论。请忽略。会检查的
    • 我想将输出作为百分比附加到df['Matched Percent'] 列。我尝试了您的第二个代码,但它给了我错误。 ValueError: Unknown format code 'f' for object of type 'str'我的python版本是3.6.5
    • 使用赋值:df['Matched Percent'] = df['Matched Percent']*100).map(lambda x: f'{x:.0f}% Matched')。你在滥用append,事实上append应该很少被使用。
    • 完美。你的答案就像魔术一样。运行时间非常快。非常感谢。_/\_
    【解决方案2】:

    如果我正确理解您的问题,

    df = pd.DataFrame({ 'Col1':[['Phone', 'Watch', 'Pen', 'Pencil', 'Knife'],
                                ['apple','orange','mango','cherry','banana','kiwi','tomato','avocado']], 
                          'Col2': [['Phone', 'Watch', 'Pen', 'Pencil', 'fork'],
                                   ['orange','avocado','kiwi','mango','grape','lemon','tomato']]})
    
    df['Matched Percent'] = 'No Match'
    
    for index,(lst1,lst2) in enumerate(zip(df['Col1'],df['Col2'])):
        if(lst1 == lst2):
            print('100% Matched')
            df['Matched Percent'][index] = '{}% Matched'.format(100)
        else:
            c1 = Counter(lst1)
            c2 = Counter(lst2)
            matching = {k: c1[k]+c2[k] for k in c1.keys() if k in c2}
            text = '% Matched'
            if len(lst1) > len(lst2):
                out = round(len(matching)/len(lst1)*100)
                #df['Matched Percent'].append(out,'% Matched')
                print(out,'% Matched')
                df['Matched Percent'][index] = '{}% Matched'.format(out)
            else:
                out = round(len(matching)/len(lst2)*100)
                #df['Matched Percent'].append(out,'% Matched')
                print(out,'% Matched')
                df['Matched Percent'][index] = '{}% Matched'.format(out)
    

    我希望您的 df 满足以下条件:

    import pandas as pd
    
    result = 'blablabla'
    df = pd.DataFrame(data=[[1,2,3],[4,5,6]],
                      columns=['a','b','Match Percent'])
    s = pd.Series(index=df.columns)
    df = df.append(s, ignore_index=True)
    df['Match Percent'][df.shape[0]-1] = result
    
    print(df)
    
         a    b Match Percent
    0  1.0  2.0             3
    1  4.0  5.0             6
    2  NaN  NaN     blablabla
    

    我想这就是你想要的,对吧?

    更正:

    df = pd.DataFrame(data=[[1,2],[4,5]],
                  columns=['a','b'])
    
    df['Match Percent'] = (df['a']/df['b']*100).apply(lambda x: '{} Match'.format(x))
    
    
       a  b Match Percent
    0  1  2    50.0 Match
    1  4  5    80.0 Match
    

    【讨论】:

    • 感谢您的回答。事实上,我正在计算两列中匹配的字符串的百分比。所以如果你看看我的问题。我已经找到了匹配的。我将len(matching)(匹配字符串的数量)除以len(text)(实际字符串的总数)。我可以将输出打印为40% matched。但是当我通过将它放在一个名为result 的变量中来附加这个40% Matched 时。追加失败并出现类型错误。所以在你的例子中。 Match Percent 列应该显示 50% Matched,这不过是 a/b*100。我希望它清楚。
    • 更正上述引用您的示例的语句。如果列 a 包含匹配值的数量为 1.0 并且 b 包含值的总数。那么匹配的百分比将是a/b*100
    • a 列中的值为1 和b 列中的值为2 时,我不明白您的百分比如何导致0.02 match。如果 2 个中有一个匹配项,那么它必须是 50% match 对吗?
    • 抱歉,在此之前我输入 df['a']*df['b'] 而不是 df['a']/df['b'],我没有编辑输出...
    • 但是你能回到我的例子吗?您已经使用您创建的测试数据框完成了它。但在我的示例中,我采用了两个列表的长度,然后尝试构建它。你认为你可以建造这样的东西吗?不幸的是,我的要求就是这样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 2014-08-02
    • 2018-08-27
    • 1970-01-01
    • 2017-12-20
    • 2015-09-15
    相关资源
    最近更新 更多