有条件地将值附加到pandas中的列表列表

bfrts1fy  于 2023-04-28  发布在  其他
关注(0)|答案(4)|浏览(115)

我尝试在pandas中有条件地附加一个列表列表:

import pandas as pd
df = pd.DataFrame(data={'A': [1, 2, 3]})
df['B'] = [[[1],[1],[1]]] * df.shape[0] 
df

       A                B
    0  1  [[1], [1], [1]]
    1  2  [[1], [1], [1]]
    2  3  [[1], [1], [1]]

# attempting to append 1st list of lists in B column with 2
df['B'] = df['B'].mask(df.A == 2, df['B'].apply(lambda x: x[0].append(2)))
df
       A                         B
    0  1  [[1, 2, 2, 2], [1], [1]]
    1  2                      None
    2  3  [[1, 2, 2, 2], [1], [1]]

#expected result I'm hoping for is: 
df['B'] = [[[1],[1],[1]],[[1,2],[1],[1]],[[1],[1],[1]]]
df

       A                   B
    0  1     [[1], [1], [1]]
    1  2  [[1, 2], [1], [1]]
    2  3     [[1], [1], [1]]
yduiuuwa

yduiuuwa1#

尝试使用lambda函数有条件地修改列表列表,如下所示:

import pandas as pd

df = pd.DataFrame(data={'A': [1, 2, 3]})
df['B'] = [[[1],[1],[1]]] * df.shape[0] 

df['B'] = df.apply(lambda row: row['B'] if row['A'] != 2 else [row['B'][0] + [2]] + row['B'][1:], axis=1)

print(df)

在这里,我们创建一个新的列表列表,其中包括修改后的列表,然后返回该列表。apply方法在axis=1的整个DataFrame上调用,以按行应用lambda函数。

68bkxrlz

68bkxrlz2#

list.append在适当的位置工作,所以它实际上返回None而不是一个列表。这就是为什么你的新df在第二行有None
下面是一个将2添加到列表中的方法。我们取第二行中的第一个列表并添加[2],然后解包其余的列表以形成预期的输出:

df['B'].mask(df['A'].eq(2),lambda x: x.map(lambda x: [x[0] + [2],*x[1:]]))

输出:

0       [[1], [1], [1]]
1    [[1, 2], [1], [1]]
2       [[1], [1], [1]]
kyvafyod

kyvafyod3#

import pandas as pd
import copy

df = pd.DataFrame(data={'A': [1, 2, 3]})
df['B'] = [[[1],[1],[1]]] * df.shape[0] 

i,j = 1,1
l = copy.deepcopy(df.iat[i, j]) # Deepcopy to avoid pointer problem
l[0] = [1,2]
df.iat[i, j] = l

print(df)
A                   B
0  1     [[1], [1], [1]]
1  2  [[1, 2], [1], [1]]
2  3     [[1], [1], [1]]
iswrvxsc

iswrvxsc4#

问题在于如何生成数据框:

import pandas as pd
df = pd.DataFrame(data={'A': [1, 2, 3]})
df['B'] = [[[1],[1],[1]]] * df.shape[0] 
df

[[[1],[1],[1]]] * df.shape[0]在Python中是一个棘手的东西。因为df中不同行的所有[[1],[1],[1]]都指向同一个对象,即列表[[1], [1], [1]]
试试这个:

df.at[1, 'B'][0] = [1, 2]

.at[ ]允许您同时使用索引号和列名进行访问。[0]选择访问后返回的列表的第一个元素。所以这里不需要lambda
我们认为只有第二行的'B'列'列表中的第一个元素[[1], [1], [1]]被更改为[[1, 2], [1], [1]]。但如果你看整个数据框:

df

它返回:

A                   B
0  1  [[1, 2], [1], [1]]
1  2  [[1, 2], [1], [1]]
2  3  [[1, 2], [1], [1]]

因为B中的元素都指向同一个对象,所以它们会同时发生变异。
这就是为什么在生成这样的构造时应该避免[ ] * <number>
相反,使用e。g.列表理解:

import pandas as pd
df = pd.DataFrame(data={'A': [1, 2, 3]})
df['B'] = [[[1],[1],[1]] for _ in range(df.shape[0])] 
df

# and mutate by:
df.at[1, 'B'][0] = [1, 2]

df

   A                   B
0  1     [[1], [1], [1]]
1  2  [[1, 2], [1], [1]]
2  3     [[1], [1], [1]]

避免在lambda中使用append

怎么样:

import pandas as pd
df = pd.DataFrame(data={'A': [1, 2, 3]})
df['B'] = [[[1],[1],[1]] for _ in range(df.shape[0])] 
df

import copy

def myfun(x):
    l = copy.deepcopy(x)
    l[0] = l[0] + [2]
    return l
    
df.at[1, 'B'] = myfun(df.at[1, 'B']) 

df

   A                   B
0  1     [[1], [1], [1]]
1  2  [[1, 2], [1], [1]]
2  3     [[1], [1], [1]]

可以使用np.where()来获取行索引:

df.at[np.where(df['A'] == 2)[0][0], 'B'] = myfun(df.at[np.where(df['A'] == 2)[0][0], 'B'])

相关问题