Pivot pandas dataframe 从单行到每行一行

Pivot pandas dataframe from single row to one row per item

我最近应用了一个转换来取消嵌套嵌套 json,以便使用一个平面数据集,虽然转换有效,但最终格式不是我正在寻找的格式。它将所有数据压缩成一行,并为列名添加后缀,而不是将每个 id_prop.

分成不同的列

我的 JSON 格式的数据集要用 Pandas 复制:

import pandas as pd
json = {"id_prop.0":{"0":1},"id_prop.1":{"0":2},"id_prop.2":{"0":3},"prop_number.0":{"0":123},"prop_number.1":{"0":325},"prop_number.2":{"0":754},"prop_value.0":{"0":1},"prop_value.1":{"0":1},"prop_value.2":{"0":1}}
df = pd.DataFrame.from_dict(json, orient='columns')

我的结果:

id_prop.0 id_prop.1 id_prop.2 prop_number.0 prop_number.1 prop_number.2 prop_value.0 prop_value.1 prop_value.2
0 1 2 3 123 325 754 1 1 1

我期望的结果:

id_prop prop_number prop_value
0 1 123 1
1 2 325 1
2 3 754 1

有什么方法可以将数据帧转换成我需要的格式,其中每一行代表单个 id_prop?

的值

尝试

我已经提取了我需要的不带后缀的列的名称:

def extract_cols(columns):
    myset = set()
    myset_add = myset.add
    return [x for x in columns if not (x in myset or myset_add(x))]

cols = extract_cols(df.columns.str.replace("\.[0-9]", "", regex=True))

并且还“垂直化”了我需要使用 stack():

的结果
df_stacked = df.stack().reset_index(level=1, drop=True)

但我还没有想出如何组合这些信息。任何帮助将不胜感激。

额外:

如果还有一种方法可以使用 pyspark 来应用它,那就更好了!

您可以将列拆分为多索引,然后将其堆叠:

df.set_axis(
    pd.MultiIndex.from_tuples([tuple(i) for i in df.columns.str.split(".")]), axis=1
).stack().droplevel(0)

这里有一个方法:

df = df.T
df.index = pd.MultiIndex.from_arrays([[x[x.find('.')+1:] for x in df.index], [x[:x.find('.')] for x in df.index]])
df = df.unstack()

输入:

   id_prop.0  id_prop.1  id_prop.2  prop_number.0  prop_number.1  prop_number.2  prop_value.0  prop_value.1  prop_value.2
0          1          2          3            123            325            754             1             1             1

输出:

  id_prop prop_number prop_value
0       1         123          1
1       2         325          1
2       3         754          1

解释:

  • 转置以便我们可以使用索引而不是列
  • 将每个标签解析为所需的标签(前缀)和结果编号(后缀)由.字符分割
  • 将 df 的索引更新为具有两个级别的 MultiIndex:结果编号列表和所需标签列表
  • 调用 unstack 将 MultiIndex(所需标签)的一个级别旋转为列标题

UPDATE:要处理结果编号是第二个 . 分隔标记并在其右侧附加标记的标签(如 OP 评论中所述),我们可以这样做这个:

import pandas as pd
json = {
    "building.0.description.bedrooms":{"0":"qrs"}, 
    "building.1.description.bedrooms":{"0":"tuv"}, 
    "building.2.description.bedrooms":{"0":"xyz"}, 

    "id_prop.0":{"0":1},"id_prop.1":{"0":2},"id_prop.2":{"0":3},
    "prop_number.0":{"0":123},"prop_number.1":{"0":325},"prop_number.2":{"0":754},
    "prop_value.0":{"0":1},"prop_value.1":{"0":1},"prop_value.2":{"0":1}}
df = pd.DataFrame.from_dict(json, orient='columns')
print(df.to_string())

df = df.T
df.index = pd.MultiIndex.from_arrays([[x.split('.')[1] for x in df.index], ['.'.join(x.split('.')[0:1] + x.split('.')[2:]) for x in df.index]])
df = df.unstack()
df.columns = df.columns.get_level_values(1)
print(df)

输入:

  building.0.description.bedrooms building.1.description.bedrooms building.2.description.bedrooms  id_prop.0  id_prop.1  id_prop.2  prop_number.0  prop_number.1  prop_number.2  prop_value.0  prop_value.1  prop_value.2
0                             qrs                             tuv                             xyz          1          2          3            123            325            754             1             1             1

输出:

  building.description.bedrooms id_prop prop_number prop_value
0                           qrs       1         123          1
1                           tuv       2         325          1
2                           xyz       3         754          1