【问题标题】:Avoid VisibleDeprecationWarning when splitting up nested ragged arrays in a Pandas DataFrame在 Pandas DataFrame 中拆分嵌套不规则数组时避免 VisibleDeprecationWarning
【发布时间】:2020-10-14 00:15:16
【问题描述】:

问题

如何在 Pandas DataFrame 中将包含嵌套不规则数组的列拆分为新列时触发VisibleDeprecationWarning普遍接受直截了当的方式,或者解释为什么现在不可能。

术语:

  • 这篇文章中的数组指的是numpy.array
  • Ragged 表示“类似列表的对象的集合”(即 list[list]、array[array]、list[tuple] 等)中的项目具有不相等数量的元素。
  • 本文中的“嵌套参差不齐的数组”意味着数组在最深的层次上参差不齐,但在最外层的两个层次中元素的数量分别相等。换句话说,它可以转换成一个二维数组,其中包含可能不等长的列表对象。

现有职位调查

经过广泛的调查以及我自己进行的实验,我找不到一种普遍接受且直接的方法。下面列出了发布时关于 SO 的两个最相关的帖子。

  • This post 抑制警告,但没有指出好的实现应该是什么。禁止警告当然通常不被认为是一种好的做法。
  • This post 也关注警告消息而不是实现。

这些帖子充其量与问题关系不大:post1post2post3post4

实验

样本 sata 和预期输出

df = pd.DataFrame(
    data={
        "id": ['a', 'b', 'c'],
        "col1": [[[1, 2], [3, 4, 5]],
                 [[6], [7, 8, 9]],
                 [[10, 11, 12], []]
                 ]
    }
)

df
Out[81]: 
  id                 col1
0  a  [[1, 2], [3, 4, 5]]
1  b     [[6], [7, 8, 9]]
2  c   [[10, 11, 12], []]

可以看到df["col1"] 在最外层的两个级别中具有 shape=(3, 2)。预期输出:

df  # expected output  
Out[177]: 
  id                 col1          sep1       sep2
0  a  [[1, 2], [3, 4, 5]]        [1, 2]  [3, 4, 5]
1  b     [[6], [7, 8, 9]]           [6]  [7, 8, 9]
2  c   [[10, 11, 12], []]  [10, 11, 12]         []

为了节省时间,可以直接跳到最后一小节开始工作方法。下面按时间顺序介绍了我尝试过的所有相关策略。

主要试验

这里的分割函数产生了一个二元组的pd.Series,这是合理的。

df["col1"].apply(lambda el: (el[0], el[1]))
Out[82]: 
0    ([1, 2], [3, 4, 5])
1       ([6], [7, 8, 9])
2     ([10, 11, 12], [])
Name: col1, dtype: object

但是,直接分配到单独的列会产生ValueError

df[["sep1", "sep2"]] = df["col1"].apply(lambda el: (el[0], el[1]))

Traceback (most recent call last):
  File "/opt/anaconda3/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3417, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-75-973c44fe294a>", line 1, in <module>
    df[["sep1", "sep2"]] = df["col1"].apply(lambda el: (el[0], el[1]))
  File "/opt/anaconda3/lib/python3.7/site-packages/pandas/core/frame.py", line 3037, in __setitem__
    self._setitem_array(key, value)
  File "/opt/anaconda3/lib/python3.7/site-packages/pandas/core/frame.py", line 3072, in _setitem_array
    self.iloc._setitem_with_indexer((slice(None), indexer), value)
  File "/opt/anaconda3/lib/python3.7/site-packages/pandas/core/indexing.py", line 1755, in _setitem_with_indexer
    "Must have equal len keys and value "
ValueError: Must have equal len keys and value when setting with an iterable

这可以通过使用.tolist()Series 转换为list 来避免。

df["col1"].apply(lambda el: (el[0], el[1])).tolist()
Out[84]: [([1, 2], [3, 4, 5]), ([6], [7, 8, 9]), ([10, 11, 12], [])]

现在直接分配可以正常工作,但会弹出一个VisibleDeprecationWarning

df[["sep1", "sep2"]] = df["col1"].apply(lambda el: (el[0], el[1])).tolist()

/opt/anaconda3/lib/python3.7/site-packages/numpy/core/_asarray.py:83: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  return array(a, dtype, copy=False, order=order)

df  # this is expected
Out[86]: 
id                 col1          sep1       sep2
0  a  [[1, 2], [3, 4, 5]]        [1, 2]  [3, 4, 5]
1  b     [[6], [7, 8, 9]]           [6]  [7, 8, 9]
2  c   [[10, 11, 12], []]  [10, 11, 12]         []

list-zip-star 方法

ValueErrorVisibleDeprecationWarning

ls = df["col1"].apply(lambda el: (el[0], el[1])).tolist()
unpacked = list(zip(*ls))

df[["sep1", "sep2"]] = unpacked
# same ValueError message as above

df["sep1"] = unpacked[0]
# same VisibleDeprecationWarning message as above

list-map-list-zip-star 方法(有效但...)

只需随机添加另一层list-map。这一次,终于可以得到想要的输出了。但这在以下方面非常违反直觉:

  1. 必须单独分配新列。为什么不能一次完成?
  2. list-map-list-zip-star 功能非常令人费解。

我真的应该按设计这样做吗?

ls = df["col1"].apply(lambda el: (el[0], el[1])).tolist()
unpacked = list(map(list, zip(*ls)))  # a magical spell

df[["sep1", "sep2"]] = unpacked
# same ValueError message. Why?

# set the new columns individually.
df["sep1"] = unpacked[0]
df["sep2"] = unpacked[1]

df  # expected output  
Out[177]: 
  id                 col1          sep1       sep2
0  a  [[1, 2], [3, 4, 5]]        [1, 2]  [3, 4, 5]
1  b     [[6], [7, 8, 9]]           [6]  [7, 8, 9]
2  c   [[10, 11, 12], []]  [10, 11, 12]         []

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    为什么不试试DataFrame

    df =  df.join(pd.DataFrame(df["col1"].apply(lambda el: (el[0], el[1])).tolist(), 
                  index = df.index, 
                  columns = ["sep1", "sep2"]))
    

    【讨论】:

      【解决方案2】:

      怎么样:

      df.join(pd.DataFrame(df['col1'].to_list(), 
                           columns=['sep1','sep2'],index=df.index) 
              )
      

      输出:

        id                 col1          sep1       sep2
      0  a  [[1, 2], [3, 4, 5]]        [1, 2]  [3, 4, 5]
      1  b     [[6], [7, 8, 9]]           [6]  [7, 8, 9]
      2  c   [[10, 11, 12], []]  [10, 11, 12]         []
      

      【讨论】:

        猜你喜欢
        • 2021-05-10
        • 1970-01-01
        • 1970-01-01
        • 2016-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-07
        相关资源
        最近更新 更多