pandas 列表理解若干帧

gk7wooem  于 2023-05-27  发布在  其他
关注(0)|答案(1)|浏览(98)

我将通过使用pd.DataFrames来询问这个问题,因为问题是在使用它们时出现的。但它可以推广到Python中的可变对象。
我想创建一个值不同的 Dataframe 列表。目前我做的是:

data = pd.DataFrame(np.full((2, 2), 0), columns=['A', 'B'])
list_of_frames = []
for i in range(3):
    tmp = data.copy()
    tmp.loc[0, 'A'] = i
    list_of_frames.append(tmp)

我真的很想把它写成一个列表理解。例如:

[data.loc_set_copy([0, 'A'], i) for i in range(3)]

由于我目前正在pd.DataFrame之上开发自己的模块,所以我考虑在自己的类中实现这个方法。我的类是围绕pd.DataFrame组成的,没有从pd.DataFrame继承
它为许多DataFrame方法提供了 Package 器,特别是lociloc,它们的行为方式与pd.DataFrames相同。
现在我有两个解决方案:

普通方法

def loc_set_copy(self, key, value):
    new = self.copy()
    new.loc[key[0], key[1]] = value
    return new

这允许:

[instance_of_my_class.loc_set_copy([0, 'A'], i) for i in range(3)]

问题是不支持切片。所以如果我想改变整个列:

[instance_of_my_class.loc_set_copy([:, 'A'], i) for i in range(3)]

我得到一个语法错误。

疯狂解决方案

我定义了下面的helper类:

class _Loc_Set_Copy():
    def __init__(self, molecule):
        self.data = data

    def __getitem__(self, key):
        new = self.data.copy()
        new.loc[key[0], key[1]] = key[2]
        return new

在我的类定义中,我有:

class my_class():
      def __init__(self):
          self.loc_set_copy = _Loc_Set_Copy(self)

现在我可以用途:

[instance_of_my_class.loc_set_copy[:, 'A', i] for i in range(3)]

我知道这是对语法的滥用。有没有其他方法可以做到这一点,或者我应该在一开始就依靠for循环?

e4eetjau

e4eetjau1#

当然你可以传递一个slice,使用一个slice对象:

>>> [loc_set_copy(data, [slice(None), 'A'], i) for i in range(3)]
[   A    B
0  0  0.0
1  0  0.0,    A    B
0  1  0.0
1  1  0.0,    A    B
0  2  0.0
1  2  0.0]

更漂亮的是:

>>> from pprint import pprint
>>> pprint([loc_set_copy(data, [slice(None), 'A'], i) for i in range(3)])
[   A    B
0  0  0.0
1  0  0.0,
    A    B
0  1  0.0
1  1  0.0,
    A    B
0  2  0.0
1  2  0.0]
>>>

注意事项:

>>> data.loc[:, 'A']
0    0.0
1    0.0
Name: A, dtype: float64
>>> data.loc[slice(None), 'A']
0    0.0
1    0.0
Name: A, dtype: float64

从本质上讲,切片表示法是将slice对象传递给__getitem__的语法糖:

>>> x = list(range(22))
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
>>> x[0:10:2]
[0, 2, 4, 6, 8]
>>> x[slice(0,10,2)]
[0, 2, 4, 6, 8]
>>> x.__getitem__(slice(0,10,2))
[0, 2, 4, 6, 8]
>>>

注意,鉴于上述情况,您可以将方法简化为:

>>> def loc_set_copy(self, key, value):
...     new = self.copy()
...     new.loc[key] = value
...     return new
...

如果您小心地为key参数传递tuple s:

>>> pprint([loc_set_copy(data, (0, 'A'), i) for i in range(3)])
[     A    B
0  0.0  0.0
1  0.0  0.0,
      A    B
0  1.0  0.0
1  0.0  0.0,
      A    B
0  2.0  0.0
1  0.0  0.0]
>>> pprint([loc_set_copy(data, (slice(None), 'A'), i) for i in range(3)])
[   A    B
0  0  0.0
1  0  0.0,
    A    B
0  1  0.0
1  1  0.0,
    A    B
0  2  0.0
1  2  0.0]
>>>

以下内容现在应该是完全有意义的:

>>> class A:
...   def __getitem__(self, key):
...     print(type(key))
...     print(key)
...
>>> a = A()
>>> a[1]
<class 'int'>
1
>>> a[[1]]
<class 'list'>
[1]
>>> a[object()]
<class 'object'>
<object object at 0x1003932e0>
>>>
>>> a[:1]
<class 'slice'>
slice(None, 1, None)
>>> a[:]
<class 'slice'>
slice(None, None, None)
>>> a[:,:,1:4]
<class 'tuple'>
(slice(None, None, None), slice(None, None, None), slice(1, 4, None))
>>> a[:,:,[1,2]]
<class 'tuple'>
(slice(None, None, None), slice(None, None, None), [1, 2])
>>> a[:,object():,[1,2]]
<class 'tuple'>
(slice(None, None, None), slice(<object object at 0x1003932e0>, None, None), [1, 2])
>>>

相关问题