【问题标题】:How to insert a multidimensional numpy array to pandas column?如何将多维 numpy 数组插入到 pandas 列?
【发布时间】:2019-06-16 10:43:42
【问题描述】:

我有一些 numpy 数组,其行数 (axis=0) 与 pandas 数据框的行数相同。

我想在数据框中创建一个新列,其中每个条目都是一个较小维度的 numpy 数组。

代码:

    some_df = pd.DataFrame(columns=['A'])
    for i in range(10):
        some_df.loc[i] = [np.random.rand(4, 6, 8)

    data = np.stack(some_df['A'].values)  #shape (10, 4, 6, 8)
    processed = np.max(data, axis=1)  # shape (10, 6, 8)

    some_df['B'] = processed  # This fails

我希望新列 'B' 包含形状为 (6, 8) 的 numpy 数组

如何做到这一点?

【问题讨论】:

  • 这不是您第一个关于在 DataFrame 单元格中存储 NumPy 数组的问题——在 stackoverflow.com/questions/56617760 中,我最近建议这是错误的方法。这仍然是错误的方法。
  • @JohnZwinck 即使这是错误的方法,这仍然是我现在想做的。
  • 原因是我想要一些不需要我调试索引的快速的东西。我现在根本买不起。
  • 我同意上面的评论,不推荐,但也许some_df['B'] = [x for x in processed] 应该可以工作。
  • some_df['B'] = processed.tolist()

标签: python arrays pandas numpy


【解决方案1】:

这个不推荐,很痛苦,速度慢,后期处理也不容易。

一种可能的解决方案是使用列表推导:

some_df['B'] = [x for x in processed]

或转换为列表并赋值:

some_df['B'] = processed.tolist()

【讨论】:

    【解决方案2】:

    2 年后回到这一点,这里有一个更好的做法:

    from itertools import product, chain
    import pandas as pd
    import numpy as np
    from typing import Dict
    
    
    def calc_col_names(named_shape):
        *prefix, shape = named_shape
        names = [map(str, range(i)) for i in shape]
        return map('_'.join, product(prefix, *names))
    
    
    def create_flat_columns_df_from_dict_of_numpy(
            named_np: Dict[str, np.array],
            n_samples_per_np: int,
    ):
        named_np_correct_lenth = {k: v for k, v in named_np.items() if len(v) == n_samples_per_np}
        flat_nps = [a.reshape(n_samples_per_np, -1) for a in named_np_correct_lenth.values()]
        stacked_nps = np.column_stack(flat_nps)
        named_shapes = [(name, arr.shape[1:]) for name, arr in named_np_correct_lenth.items()]
        col_names = [*chain.from_iterable(calc_col_names(named_shape) for named_shape in named_shapes)]
        df = pd.DataFrame(stacked_nps, columns=col_names)
        df = df.convert_dtypes()
        return df
    
    
    def parse_series_into_np(df, col_name, shp):
        # can parse the shape from the col names
        n_samples = len(df)
        col_names = sorted(c for c in df.columns if col_name in c)
        col_names = list(filter(lambda c: c.startswith(col_name + "_") or len(col_names) == 1, col_names))
        col_as_np = df[col_names].astype(np.float).values.reshape((n_samples, *shp))
        return col_as_np
    

    将 ndarray 放入 Dataframe 的用法:

    full_rate_df = create_flat_columns_df_from_dict_of_numpy(
        named_np={name: np.array(d[name]) for name in ["name1", "name2"]},
        n_samples_per_np=d["name1"].shape[0]
    )
    

    其中d 是相同shape[0] 的nd 数组的字典,由["name1", "name2"] 散列。

    反向操作可以通过parse_series_into_np获取。


    接受的答案仍然存在,因为它回答了原始问题,但这是一种更好的做法。

    【讨论】:

      【解决方案3】:

      我知道这个问题已经有了答案,但我想添加一种更具可扩展性的方法来解决这个问题。如上面的 cmets 所述,通常不建议将数组作为“字段”值存储在 pandas-Dataframe 列中(我实际上不知道为什么?)。然而,在我的日常工作中,当处理时间序列数据和一堆相关的元数据时,这是一个非常重要的功能。 一般来说,我以 pandas 数据帧的形式组织我的实验时间序列,其中一列包含相同长度的 numpy 数组,另一列包含有关某些测量条件等的元数据信息。

      jezrael 提出的解决方案效果很好,在过去的 4 年里我经常使用它。但是这种方法可能会遇到巨大的内存问题。就我而言,我在处理超过 500 万行的数据帧和大约 500 万行的时间序列时遇到了这些问题。 100 个数据点。

      这些问题的解决方案非常简单,因为我在任何地方都找不到它,我只想在这里分享它:只需将您的 2D 数组转换为 pandas-Series 对象并将其分配给您的数据框的列:

      df["new_list_column"] = pd.Series(list(numpy_array_2D))
      

      【讨论】:

      • 我这样做过一次,再也没有。原因(你问为什么)是这会让你失去所有的 pandas 功能,因为数字类型是预期的,这会强制对象类型。我现在要做的是将数组拆分为多列,并将第一个维度作为 pandas 中的索引。这保留了 pandas 的功能,以后可以通过列的智能命名将其聚合回 numpy ndarray。
      • 这也会在您每次想要访问数据时强制调用np.concatenate(),并且不允许绘制或查看错误或使用 Pycharm 的“作为数据框查看”或 pandas 提供的任何其他内容。为了你的理智 - 不要这样做。
      猜你喜欢
      • 2019-03-12
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 2019-05-05
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多