将一列空列表添加到 DataFrame

Posted

技术标签:

【中文标题】将一列空列表添加到 DataFrame【英文标题】:Add column of empty lists to DataFrame 【发布时间】:2015-10-06 15:22:10 【问题描述】:

类似于这个问题How to add an empty column to a dataframe?,我很想知道 的最佳方法。

我要做的基本上是初始化一列,并在遍历行以处理其中一些行时,然后在此新列中添加一个填充列表以替换初始化值。

例如,如果下面是我的初始DataFrame:

df = pd.DataFrame(d = 'a': [1,2,3], 'b': [5,6,7]) # Sample DataFrame

>>> df
   a  b
0  1  5
1  2  6
2  3  7

然后我想最终得到这样的结果,其中每一行都被单独处理(显示示例结果):

>>> df
   a  b          c
0  1  5     [5, 6]
1  2  6     [9, 0]
2  3  7  [1, 2, 3]

当然,如果我尝试像使用任何其他常量一样初始化 df['e'] = [],它认为我正在尝试添加长度为 0 的项目序列,因此会失败。

如果我尝试将新列初始化为 NoneNaN,则在尝试将列表分配给位置时会遇到以下问题。

df['d'] = None

>>> df
   a  b     d
0  1  5  None
1  2  6  None
2  3  7  None

问题 1(如果我能让这种方法发挥作用,那将是完美的!也许我缺少一些微不足道的东西):

>>> df.loc[0,'d'] = [1,3]

...
ValueError: Must have equal len keys and value when setting with an iterable

问题 2(此问题有效,但并非没有警告,因为不能保证按预期工作):

>>> df['d'][0] = [1,3]

C:\Python27\Scripts\ipython:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

因此,我使用空列表进行初始化并根据需要扩展它们。我可以想到几种方法来初始化这种方式,但有没有更直接的方法?

方法一:

df['empty_lists1'] = [list() for x in range(len(df.index))]

>>> df
   a  b   empty_lists1
0  1  5             []
1  2  6             []
2  3  7             []

方法二:

 df['empty_lists2'] = df.apply(lambda x: [], axis=1)

>>> df
   a  b   empty_lists1   empty_lists2
0  1  5             []             []
1  2  6             []             []
2  3  7             []             []

问题摘要:

是否有任何可以在问题 1 中解决的细微语法更改可以允许将列表分配给 None/NaN 初始化字段?

如果不是,那么用空列表初始化新列的最佳方法是什么?

【问题讨论】:

在第 1 期和第 2 期中,您开始引用 d 列。那是什么意思? 以及它的价值我喜欢方法 2。非常简单的 imo。 Column 'd' 只是 NoneNaN 初始化值的列,正如问题之前定义的那样。 是否有任何可以在问题 1 中解决的细微语法更改,允许将列表分配给 None/NaN 初始化字段? 【参考方案1】:

还有一种方法是使用np.empty

df['empty_list'] = np.empty((len(df), 0)).tolist()

您也可以在“方法 1”中尝试查找 len 中的 df 时取消 .index

df['empty_list'] = [[] for _ in range(len(df))]

事实证明,np.empty 更快...

In [1]: import pandas as pd

In [2]: df = pd.DataFrame(pd.np.random.rand(1000000, 5))

In [3]: timeit df['empty1'] = pd.np.empty((len(df), 0)).tolist()
10 loops, best of 3: 127 ms per loop

In [4]: timeit df['empty2'] = [[] for _ in range(len(df))]
10 loops, best of 3: 193 ms per loop

In [5]: timeit df['empty3'] = df.apply(lambda x: [], axis=1)
1 loops, best of 3: 5.89 s per loop

【讨论】:

谢谢。是的,np.empty 方法看起来确实更快。 len(df.index) 实际上也比 len(df) 更快。 pd.np 已弃用。导入并使用 np 代替 github.com/pandas-dev/pandas/pull/30489【参考方案2】:

编辑:评论者在我的回答中发现了错误

s = pd.Series([[]] * 3)
s.iloc[0].append(1) #adding an item only to the first element
>s # unintended consequences:
0    [1]
1    [1]
2    [1]

所以,正确的解决方案是

s = pd.Series([[] for i in range(3)])
s.iloc[0].append(1)
>s
0    [1]
1     []
2     []

旧:

我在接受的答案中对所有三种方法都进行了计时,最快的一种在我的机器上花费了 216 毫秒。然而,这仅用了 28 毫秒:

df['empty4'] = [[]] * len(df)

注意:同样,df['e5'] = [set()] * len(df) 也需要 28 毫秒。

【讨论】:

我已经尝试了 2 个小时来解决这个问题,这个解决方案是真正的解决方案。 所有这些列表都是同一个对象。设置一个单元格将设置所有单元格。 df['empty_list'] = [[] for _ in range(len(df))] 更好。 这是不正确的,这会将所有行分配给同一个列表引用,这意味着如果您追加到其中一个列表,这与一次追加到它们没有什么不同 - 您需要初始化单独的空通过列表推导列出。【参考方案3】:

规范解决方案:列表理解,mapapply

强制性免责声明:尽可能避免在 pandas 列中使用列表,列表列处理起来很慢,因为它们是对象,而且它们本质上很难矢量化。

除此之外,以下是引入一列空列表的规范方法:

# List comprehension
df['c'] = [[] for _ in range(df.shape[0])]
df

   a  b   c
0  1  5  []
1  2  6  []
2  3  7  []

还有这些简写涉及applymap

from collections import defaultdict
# map any column with defaultdict
df['c'] = df.iloc[:,0].map(defaultdict(list))
# same as,
df['c'] = df.iloc[:,0].map(lambda _: [])

# apply with defaultdict
df['c'] = df.apply(defaultdict(list), axis=1) 
# same as,
df['c'] = df.apply(lambda _: [], axis=1)

df

   a  b   c
0  1  5  []
1  2  6  []
2  3  7  []

你不应该做的事情

有些人认为乘以一个空列表是可行的方法,不幸的是这是错误的,通常会导致难以调试的问题。这是一个 MVP:

# WRONG
df['c'] = [[]] * len(df) 
df.at[0, 'c'].append('abc')
df.at[1, 'c'].append('def')
df

   a  b           c
0  1  5  [abc, def]
1  2  6  [abc, def]
2  3  7  [abc, def]

# RIGHT
df['c'] = [[] for _ in range(df.shape[0])]
df.at[0, 'c'].append('abc')
df.at[1, 'c'].append('def')
df

a  b      c
0  1  5  [abc]
1  2  6  [def]
2  3  7     []

在第一种情况下,创建了一个空列表,并且它的 reference 被复制到所有行中,因此您会看到对所有行的更新。在后一种情况下,每一行都被分配了自己的空列表,所以这不是问题。

【讨论】:

以上是关于将一列空列表添加到 DataFrame的主要内容,如果未能解决你的问题,请参考以下文章

如何将一列中的单词拆分然后在Python中将单词整合在一起,即二维列表到一维列表?

使用 pivot_table 将一列 dict 聚合到一个 dict 列表中 - Pandas

将一列添加到功能集

将一列从一个数据集中添加到另一个

如何将一列的运行总计添加到 Access 查询?

有没有更快的方法将一列 pyspark 数据框转换为 python 列表? (Collect() 非常慢)