Flatten DataFrame 嵌套 list/array 带有额外的索引键(对于时间序列)
Flatten DataFrame nested list/array with extra index keys (for time series)
我有一个 DataFrame 结构如下。 (这是 JSON 归一化的结果)
mydf
id colA colB ... colArray
foo a1 b1 [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
bar a2 b2 [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
fooz a3 b3 [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
barz a4 b4 [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
date
是时间戳
colArray
行中的每个数组长度不同,但数组元素结构完全相同
['id', 'colA', 'colB']
是我想用作唯一索引的列的示例
我想转换这些数据以便将它们用作时间序列。
我想要的输出是这样的:
id colA colB ... date data1 data2 ... data n
foo a1 b1 '1st timestamp' 'flex' 0.1
foo a1 b1 '...'
...
foo a1 b1 'last_timestamp'
bar a2 b2 '1st timestamp' 'zorg'
bar a2 b2 '...'
...
bar a2 b2 'last_timestamp'
fooz a3 b3 '...'
fooz a3 b3 '...'
...
fooz a3 b3 '...'
etc.
这将允许我 plot/analyze 基于元组的时间序列,例如 [foo, a1, b1]
对我来说,这看起来与 非常相似,但接受的答案令人沮丧:JSON/dict 数据并未真正处理以生成具有正确数据的 DataFrame。
有没有人对如何实现这一目标有任何建议?
第一种方法
使用下面的,接近我想要的:
tmpdf = pd.DataFrame(mydf['colArray'].tolist())
json_normalize(tmpdf[0])
但是有两个问题:
- 我丢失了我想用作唯一标识符的
['id', 'colA', 'colB']
元组。
- 我需要对我的 tmpdf 的每一行执行操作
第二种方法
基于Accessing nested JSON data as dataframes in Pandas
pd.concat(pd.DataFrame.from_dict(tmp_array) for array in mydf['colArray'])
它给了我一个数据框,其中所有数组都被展平,列名正确,但我丢失了相应的键(['id', 'colA', 'colB']
)。
我觉得这是正确的方法,但我不知道如何保留索引列(以便我可以通过索引列过滤每个结果时间序列)。
可惜没有"json_melt"功能
第三种方法
基于这个问题。
我可以保留我的索引列,但数组元素仍在 JSON 中并且索引为 [0, 1, 2, ...]。我将无法处理可变长度(对于列索引的较高值有很多 NA
参考书目:
Create a Pandas DataFrame from deeply nested JSON 但解决方案是基于原始的 JSON 处理,而我想在现有的 DataFrame
上执行此操作
Accessing nested JSON data as dataframes in Pandas这与我想要的非常接近。
结果看起来像我的第一次尝试,但底层 JSON 数据并没有真正 "matrixed" 到数据帧中。
A rather complex and not satisfaying approach
编辑: 但是在询问时,我无法通过搜索找到它。供将来参考?
对 MulltiIndex
:
使用 pop
for extract original column and concat
的字典理解
df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()})
替代方法是使用参数 keys
:
df = pd.concat([pd.DataFrame(array) for array in mydf.pop('colArray')], keys=mydf.index)
然后删除第二层,这样可以 join
与原来的 DataFrame
:
df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True)
样本:
mydf = pd.DataFrame({'id': ['foo', 'bar', 'fooz', 'barz'], 'colA': ['a1', 'a2', 'a3', 'a4'], 'colB': ['b1', 'b2', 'b3', 'b4'], 'colArray': [[{'date': 's', 'data1': 't', 'data2': 0.1}, {'date': 'd', 'data1': 'r', 'data2': 0.8}], [{'date': 'd', 'data1': 'y', 'data2': 0.1}], [{'date': 'g', 'data1': 'u', 'data2': 0.1}], [{'date': 'h', 'data1': 'i', 'data2': 0.1}]]})
print (mydf)
id colA colB colArray
0 foo a1 b1 [{'date': 's', 'data1': 't', 'data2': 0.1}, {'...
1 bar a2 b2 [{'date': 'd', 'data1': 'y', 'data2': 0.1}]
2 fooz a3 b3 [{'date': 'g', 'data1': 'u', 'data2': 0.1}]
3 barz a4 b4 [{'date': 'h', 'data1': 'i', 'data2': 0.1}]
df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()})
print (df)
data1 data2 date
0 0 t 0.1 s
1 r 0.8 d
1 0 y 0.1 d
2 0 u 0.1 g
3 0 i 0.1 h
df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True)
print (df)
data1 data2 date id colA colB
0 t 0.1 s foo a1 b1
1 r 0.8 d foo a1 b1
2 y 0.1 d bar a2 b2
3 u 0.1 g fooz a3 b3
4 i 0.1 h barz a4 b4
我有一个 DataFrame 结构如下。 (这是 JSON 归一化的结果)
mydf
id colA colB ... colArray
foo a1 b1 [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
bar a2 b2 [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
fooz a3 b3 [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
barz a4 b4 [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
date
是时间戳colArray
行中的每个数组长度不同,但数组元素结构完全相同['id', 'colA', 'colB']
是我想用作唯一索引的列的示例
我想转换这些数据以便将它们用作时间序列。 我想要的输出是这样的:
id colA colB ... date data1 data2 ... data n
foo a1 b1 '1st timestamp' 'flex' 0.1
foo a1 b1 '...'
...
foo a1 b1 'last_timestamp'
bar a2 b2 '1st timestamp' 'zorg'
bar a2 b2 '...'
...
bar a2 b2 'last_timestamp'
fooz a3 b3 '...'
fooz a3 b3 '...'
...
fooz a3 b3 '...'
etc.
这将允许我 plot/analyze 基于元组的时间序列,例如 [foo, a1, b1]
对我来说,这看起来与
有没有人对如何实现这一目标有任何建议?
第一种方法
使用下面的,接近我想要的:
tmpdf = pd.DataFrame(mydf['colArray'].tolist())
json_normalize(tmpdf[0])
但是有两个问题:
- 我丢失了我想用作唯一标识符的
['id', 'colA', 'colB']
元组。 - 我需要对我的 tmpdf 的每一行执行操作
第二种方法
基于Accessing nested JSON data as dataframes in Pandas
pd.concat(pd.DataFrame.from_dict(tmp_array) for array in mydf['colArray'])
它给了我一个数据框,其中所有数组都被展平,列名正确,但我丢失了相应的键(['id', 'colA', 'colB']
)。
我觉得这是正确的方法,但我不知道如何保留索引列(以便我可以通过索引列过滤每个结果时间序列)。
可惜没有"json_melt"功能
第三种方法
基于这个问题
参考书目: Create a Pandas DataFrame from deeply nested JSON 但解决方案是基于原始的 JSON 处理,而我想在现有的 DataFrame
上执行此操作Accessing nested JSON data as dataframes in Pandas这与我想要的非常接近。
A rather complex and not satisfaying approach
编辑:
对 MulltiIndex
:
pop
for extract original column and concat
的字典理解
df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()})
替代方法是使用参数 keys
:
df = pd.concat([pd.DataFrame(array) for array in mydf.pop('colArray')], keys=mydf.index)
然后删除第二层,这样可以 join
与原来的 DataFrame
:
df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True)
样本:
mydf = pd.DataFrame({'id': ['foo', 'bar', 'fooz', 'barz'], 'colA': ['a1', 'a2', 'a3', 'a4'], 'colB': ['b1', 'b2', 'b3', 'b4'], 'colArray': [[{'date': 's', 'data1': 't', 'data2': 0.1}, {'date': 'd', 'data1': 'r', 'data2': 0.8}], [{'date': 'd', 'data1': 'y', 'data2': 0.1}], [{'date': 'g', 'data1': 'u', 'data2': 0.1}], [{'date': 'h', 'data1': 'i', 'data2': 0.1}]]})
print (mydf)
id colA colB colArray
0 foo a1 b1 [{'date': 's', 'data1': 't', 'data2': 0.1}, {'...
1 bar a2 b2 [{'date': 'd', 'data1': 'y', 'data2': 0.1}]
2 fooz a3 b3 [{'date': 'g', 'data1': 'u', 'data2': 0.1}]
3 barz a4 b4 [{'date': 'h', 'data1': 'i', 'data2': 0.1}]
df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()})
print (df)
data1 data2 date
0 0 t 0.1 s
1 r 0.8 d
1 0 y 0.1 d
2 0 u 0.1 g
3 0 i 0.1 h
df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True)
print (df)
data1 data2 date id colA colB
0 t 0.1 s foo a1 b1
1 r 0.8 d foo a1 b1
2 y 0.1 d bar a2 b2
3 u 0.1 g fooz a3 b3
4 i 0.1 h barz a4 b4