【问题标题】:"Pivot" a Pandas DataFrame into a 3D numpy array将 Pandas 数据帧“旋转”到 3D numpy 数组中
【发布时间】:2019-12-31 16:59:21
【问题描述】:

给定一个具有以下结构的 DataFrame:

Date     | Site  | Measurement Type | Value
-----------------------------------------------
1/1/2020 | A     | Temperature      | 32.3
1/2/2020 | B     | Humidity         | 70%

我想创建一个 3D“数据透视表”,其中第一个轴代表站点,第二个轴代表日期,第三个代表测量类型,并且值存储在每个元素中。

例如,如果我在 5 个地点进行为期一周的每日测量,同时测量温度和湿度,则所需的输出将是形状为 (5, 7, 2) 的数组。

Pandas 似乎只支持创建 2D 数据透视表,但我很高兴只使用一个未标记的 3D numpy 数组作为输出。在我花时间自己实施之前,想知道是否有现有的简单方法可以做到这一点。

【问题讨论】:

  • 这听起来像是使用 MultiIndex 进行的基本旋转。这就是为什么发布预期输出也很重要的原因,因为您可以通过多种方式解决此问题。
  • 类似pd.crosstab(df.Date,columns=[df['Measurement Type'],df['Site']],values=df['Value'],aggfunc='first') ?
  • @Erfan 查看编辑 - 这是否阐明了所需的输出结构?
  • 你让这件事变得比我认为的更困难。 3d 数组很难阅读。 Pandas 使用MultiIndex 解决了这个问题,您可以使用它来实现多维。试试这个代码:df.pivot_table(index='Date', columns=['Site', 'Measurement Type'], values='Value', aggfunc=lambda x: x)
  • @Erfan 我需要 3D 结构,因为我正在为 Tensorflow 中的 RNN 训练转换数据。请参阅diagram in this tutorial for the desired structure 我同意 MultiIndex 的可读性更好。

标签: python pandas numpy pivot-table


【解决方案1】:

使用df.pivot_table 是可行的。我在您的示例中再添加一行以同时拥有Measurement Type。在缺失值上,它将由np.nan表示

sample `df`

       Date Site Measurement_Type Value
0  1/1/2020    A      Temperature  32.3
1  1/1/2020    A         Humidity   60%
2  1/2/2020    B         Humidity   70%

试试下面的

iix = pd.MultiIndex.from_product([np.unique(df.Date), np.unique(df.Measurement_Type)])
df_pivot = (df.pivot_table('Value', 'Site', ['Date', 'Measurement_Type'], aggfunc='first')
              .reindex(iix, axis=1))
arr = np.array(df_pivot.groupby(level=0, axis=1).agg(lambda x: [*x.values])
                       .to_numpy().tolist())

print(arr)

Out[1447]:
array([[['60%', '32.3'],
        [nan, nan]],

       [[nan, nan],
        ['70%', nan]]], dtype=object)

方法2:在不同的列上使用pivot_table和numpy reshape

iix_n = pd.MultiIndex.from_product([np.unique(df.Site), np.unique(df.Date)])
arr = (df.pivot_table('Value', ['Site', 'Date'], 'Measurement_Type', aggfunc='first')
         .reindex(iix_n).to_numpy()
         .reshape(df.Site.nunique(),df.Date.nunique(),-1))

Out[1501]:
array([[['60%', '32.3'],
        [nan, nan]],

       [[nan, nan],
        ['70%', nan]]], dtype=object)

【讨论】:

  • 这正是我所需要的,尽管我希望以更简单的方式实现。谢谢你。我也喜欢它如何处理丢失的数据。
  • 原生pivot_table不支持3D-array输出,所以我们需要做更多的处理来实现它。很高兴我能帮忙:)
  • @LoLa:我使用pivot_tablereshape 添加了另一种方法。它比第一个简单。如果您想要更简单的解决方案,请尝试一下。注意不同的旋转列和不同的reindex
  • 整洁,我喜欢这个。结果数组将在每个轴上排序(基于原始索引)正确吗?
  • ...是的,它是:)
【解决方案2】:

我认为您正在寻找类似panel 的东西。您也可以只使用 3-dim numpy 数组。例如使用面板:

p_dim = {}

# desired columns
cols = ['Site', 'Measurement Type']

for date in df.Date:
    sub_df = df[df.Date.isin([date])].reset_index(drop=True)
    p_dim[date] = sub_df[[c for c in sub_df.columns if c in cols]]

panel = pd.Panel(p_dim)

现在您可以使用panel['1/1/2020'] 访问与日期相关的各种数据,假设您的Date 列是str 类型。要查看所有可用密钥,您可以使用panel.keys()

【讨论】:

【解决方案3】:

我编写了一个小脚本来衡量不同 @Andy L. 方法的性能。

第二种方法似乎稍微快一点:

def pivot_table_3d_1(df, col1, col2, col3, value, aggfunc='first') :
    iix = pd.MultiIndex.from_product([np.unique(df[col2]), np.unique(df[col3])])
    df_pivot = (df.pivot_table(value, col1, [col2,col3], aggfunc=aggfunc)
                  .reindex(iix, axis=1))
    arr = np.array(df_pivot.groupby(level=0, axis=1).agg(lambda x: [*x.values])
                           .to_numpy().tolist())

    return arr

def pivot_table_3d_2(df, col1, col2, col3, value, aggfunc='first') :
    iix_n = pd.MultiIndex.from_product([np.unique(df[col1]), np.unique(df[col2])])
    arr = (df.pivot_table(value, [col1, col2], col3, aggfunc=aggfunc)
         .reindex(iix_n).to_numpy()
         .reshape(df[col1].nunique(),df[col2].nunique(),-1))

    return arr

## TESTING
N1 = 100
N2 = 200
N3 = 300
df = pd.DataFrame({'col1': np.random.randint(0, N1, N1*N2*N3),
                   'col2': np.random.randint(0, N2, N1*N2*N3),
                   'col3': np.random.randint(0, N3, N1*N2*N3),
                   'value': np.random.normal(0,1,N1*N2*N3)})

%timeit pivot_table_3d(df, col1='col1', col2='col2', col3='col3', value='value')
# 10.2 s ± 39.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit pivot_table_3d_2(df, col1='col1', col2='col2', col3='col3', value='value')
#9.47 s ± 108 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

【讨论】:

  • 感谢timeit :) +1
猜你喜欢
  • 1970-01-01
  • 2019-09-23
  • 2018-12-31
  • 1970-01-01
  • 1970-01-01
  • 2021-04-04
  • 2017-07-07
  • 2020-08-18
  • 2017-11-07
相关资源
最近更新 更多