PythonPandas:将每个单元格都作为字典的列附加到预先存在的数据框

23c0lvtd  于 2023-03-20  发布在  Python
关注(0)|答案(1)|浏览(89)

我有一个DataFrame df,格式为:

index  name      val            
0       Abc    17.29
1       Bcd  137.036
2       Cde      666

我想在df中添加一个名为"ColDict"的列,列中的每个元素都是一个字典,字典的键是str(b),因为b是任意列表list_b中的某个数字,与键str(b)匹配的值将是myfunc(df["val"], b)的输出,也就是说,对于某个浮点值函数myfunc(我已经写过了),myfunc()按照指定的顺序应用于df["val"](对于给定的行)和b。所有字典的长度都是相同的(就键数而言),因为键都属于list_b,并且穷尽了list_b
在这个例子中,为了具体,我们可以取list_b = [5, 7.6, 10, 20],但它应该是“开放式”的。同样,我们可以取myfunc(x, b),将x向下舍入到b的最大倍数,该倍数小于或等于x
在这种情况下,最终结果应如下所示:

index  name      val   ColDict            
0       Abc    17.29   {"5": myfunc(17.29, 5), "7.6": myfunc(17.29, 7.6), "10": myfunc(17.29, 10), "20": myfunc(17.29, 20)}
1       Bcd  137.036   {"5": myfunc(137.036, 5), "7.6": myfunc(137.036, 7.6), "10": myfunc(137.036, 10), "20": myfunc(137.036, 20)}
2       Cde      666   {"5": myfunc(666, 5), "7.6": myfunc(666, 7.6), "10": myfunc(666, 10), "20": myfunc(666, 20)}

其中myfunc(v, b)是浮点值输出(不是字符串“myfunc(v,B)”或任何类似字符串)。
我有三个问题:
1.第一个问题是获取一个多元变量(此处:binary)函数来应用于DataFrame列的元素。apply()map()方法似乎只适用于一元函数...我可以为此拼凑一个lambda表达式,但这似乎是一个草率的解决方案。此外,我不确定我是否正在通过此尝试的解决方案路径计算元素级,这是我想要的。
1.第二个问题是让Python接受任何新列的赋值。它一直告诉我,我试图在一个切片的副本上设置一个值。在单个固定b的情况下,我可能已经解决了这个问题,但我想知道如何以规范的方式这样做。(是的,我是Python的新手)。

  • 第三个问题是我的编译器似乎不喜欢把字典作为DataFrame中的单元格值。也许吧。它告诉我值的长度(list_b中的项数,在上面的例子中是4)与索引的长度(1 + df的最后一个索引;因此,从上面的表中,它应该是3)。也许我的代码试图以某种方式通过表进行垂直赋值,如果正确执行,字典值单元格是可以接受的?
  • 理论上,如果我解决问题#1和#2,其中n = len(list_b),我可以只为DataFrame分配n个新列,每个列的名称为"ColDict_[b]",其中b是变量。但是,我认为字典的表示方式对于我的情况来说会更清晰。但是,如果追加多个列是唯一或最好的方法,那么请教我如何这样做。但是,请注意,我也不知道如何在赋值环境中制作变量列标签(如变量b"ColDict_[b]"),所以这也必须教。

谢谢你。
到目前为止我已经尝试过:
尝试过很多东西,但这些是我到目前为止最好的尝试。
1.对于固定的b(例如:b = 5),我尝试:

df = df.assign(ColDict_5 = df["val"].map(lambda x: myfunc(x, 5)).

这至少可以编译,但我不确定这是否适用于这个特定的情况,即使适用,我仍然不能在一个步骤中将它泛化到多个b值,我也不知道这个解决方案在性能、表示或方法方面是否最好,尽管在语法操作上是如此。
1.字典理解似乎不起作用,这两种方法都失败了:
一个三个三个一个
前者失败至少是因为它试图将序列转换为浮点型,后者失败的原因是前面提到的(值的长度超过行数)。
1.如果我想分配一个固定列表(此处为:[1, 2])添加到每行的新列,则如下所示:

df = df.assign(colFixedList =  pd.Series( [[1,2]] * len(df.index) ) )

这可以概括为我的目标,但我还不确定如何使它做到这一点。

anauzrmj

anauzrmj1#

使用列表解析:

df['ColDict'] = [{str(b): myfunc(v, b) for b in list_b} for v in df['val']]

对于apply [和lambda]:

df['ColDict'] = df['val'].apply(lambda v: {str(b): myfunc(v, b) for b in list_b})
  • 我不喜欢在这里使用lambda表达式,因为我已经在其他地方定义了这个函数,需要为这个上下文定义一个单独的单变量函数感觉不对。但这可能只是个人问题 *

我仍然不能完全理解您的反感,因为将多元函数简化为一元可能是我最常用的lambda,而且我认为它非常适合;但是,我有我自己的小毛病,这很难解释,所以我可以有点同情.无论如何...您可以修改myfunc定义来处理键列表(带有一点递归),并将list_b设置为第二个参数的默认值,使其成为可选的:

# list_b = [....] # define first so that it can be used as arg2 default below

def myfunc(arg1, arg2=list_b):
    if isinstance(arg2, list):
        return {str(k): myfunc(arg1, k) for k in arg2}

    ##### continue with ORIGINAL FUNCTION BODY #####

那么你可以只使用apply而不使用lambda

df['ColDict'] = df['val'].apply(myfunc)
  • 关于如何避免“a value is trying to be set on a copy of a slice from a DataFrame”警告(这似乎无关紧要),您有什么想法吗?对我来说,这两种解决方案都有。*

如果所有的解决方案都出现这种情况,那么df本身可能就是问题所在;它是从另一个DataFrame复制/生成的吗?我不记得自己曾经遇到过这个警告,但希望关于同一消息的this thread可能会对您有所帮助。
我立即想到的第一个想法是通过使用类似下面的内容重新构造df(在添加列之前),使其成为一个独立的对象

df = pd.DataFrame.from_dict(df.to_dict('index'), orient='index')

相关问题