熊猫:将包含多行的JSON列转换为多个数据框行

时间:2020-07-30 05:11:50

标签: python json pandas

我有一个包含两列的数据框:countriesyearcountries列是JSON,格式为:

[{'continent': 'europe',
  'country': 'Yugoslavia',
  'income': None,
  'life_exp': None,
  'population': 4687422},
 {'continent': 'asia',
  'country': 'United Korea (former)',
  'income': None,
  'life_exp': None,
  'population': 13740000},
 {'continent': 'asia',
  'country': 'Tokelau',
  'income': None,
  'life_exp': None,
  'population': 1009},
  ...

如何将该数据框转换为类似的内容:

continent | country | income | life_exp | population | year
----------+---------+--------+----------+------------+-------
europe    | Yugos   | None   | None     | 4600000    | 1800
asia      | Korea   | None   ||None     | 13000000   | 1800
asia      | Tokelau | None   | None     | 1009       | 1800

是将JSON列分为几行及其相应的列,并添加与该行相对应的年份?

我在该列上使用了json_normalize(),它为我提供了我需要的列,但我不知道如何在末尾添加年份

编辑: 这是我的原始数据框:

df = pd.read_json('data.json')
print(df-head())

                                           countries  year
0  [{'continent': 'europe', 'country': 'Yugoslavi...  1800
1  [{'continent': 'europe', 'country': 'Svalbard'...  1801
2  [{'continent': 'europe', 'country': 'Svalbard'...  1802
3  [{'continent': 'asia', 'country': 'Wallis et F...  1803
4  [{'continent': 'asia', 'country': 'Wallis et F...  1804

“国家/地区”列是包含多行数据的JSON,年份适用于所有数据,那么如何将其转换为包含所有行和每一行中对应年份的数据框?

我知道,如果我执行pd.DataFrame(df.countries[0]),将产生第一行所有国家/地区的数据框,但是我不知道如何将年份添加到新列中。我认为可以这样做,但是我也想必须有一种更有效的方法


编辑:

此循环会产生我需要的结果,但我认为它效率很低:

new_df = pd.DataFrame(columns=['continent', 'country', 'income', 'life_exp', 'population', 'year'])

for i in range(len(old_df)):
    temp_df = pd.DataFrame(old_df.countries[i])
    temp_df['year'] = old_df.year[i]
    new_df = new_df.append(temp_df)

肯定有更好的方法吧?

3 个答案:

答案 0 :(得分:0)

.joinpd.json_normalize一起使用

例如:

df = pd.DataFrame(data)
df = df.join(pd.json_normalize(df.pop('countries')))
print(df)

根据评论编辑

df = pd.DataFrame(data).explode('countries')
df = df.join(pd.json_normalize(df.pop('countries')))
print(df)

输出:

   year continent                country income life_exp  population
0  1800    europe             Yugoslavia   None     None     4687422
1  1801      asia  United Korea (former)   None     None    13740000
2  1802      asia                Tokelau   None     None        1009

答案 1 :(得分:0)

您可以尝试使用explode

df=df.explode('countries')
#we add to each dictionary the respective value of year with key 'year'
df['countries']=[{**dc,**{'year':y}} for dc,y in zip(df['countries'],df['year'])]
pd.DataFrame(df['countries'].tolist())

示例

j = [{'continent': 'europe',
 'country': 'Yugoslavia',
 'income': None,
  'life_exp': None,
'population': 4687422},
{'continent': 'asia',
'country': 'United Korea (former)',
'income': None,
'life_exp': None,
'population': 13740000}]
df=pd.DataFrame({'countries':[j,j],'year':[1800,1900]})
print(df)

df=df.explode('countries')
print(df)

#Here we add the key 'year' with the respective year row value to each dictionary
df['countries']=[{**dc,**{'year':y}} for dc,y in zip(df['countries'],df['year'])]
print(df['countries'])

finaldf=pd.DataFrame(df['countries'].tolist())
print(finaldf)

输出:

original df:
                                           countries  year
0  [{'continent': 'europe', 'country': 'Yugoslavi...  1800
1  [{'continent': 'europe', 'country': 'Yugoslavi...  1900


    

df(after explode): 
                                                                                            
                                           countries  year
0  {'continent': 'europe', 'country': 'Yugoslavia...  1800
0  {'continent': 'asia', 'country': 'United Korea...  1800
1  {'continent': 'europe', 'country': 'Yugoslavia...  1900
1  {'continent': 'asia', 'country': 'United Korea...  1900


df.countries(with year added):
0    {'continent': 'europe', 'country': 'Yugoslavia', 'income': None, 'life_exp': None, 'population': 4687422, 'year': 1800}
0    {'continent': 'asia', 'country': 'United Korea (former)', 'income': None, 'life_exp': None, 'population': 13740000, 'year': 1800}
1    {'continent': 'europe', 'country': 'Yugoslavia', 'income': None, 'life_exp': None, 'population': 4687422, 'year': 1900}
1    {'continent': 'asia', 'country': 'United Korea (former)', 'income': None, 'life_exp': None, 'population': 13740000, 'year': 1900}
Name: countries, dtype: object

finaldf
  continent                country income life_exp  population  year
0    europe             Yugoslavia   None     None     4687422  1800
1      asia  United Korea (former)   None     None    13740000  1800
2    europe             Yugoslavia   None     None     4687422  1900
3      asia  United Korea (former)   None     None    13740000  1900

答案 2 :(得分:0)

您可以使用apply方法进行矢量化,然后从country列中获取相应的标记。由于您有一个名为国家的密钥,因此请在for循环之外使用它。看起来像这样

attribute = ['continent', 'income', 'life_exp', 'population']

for attr in attribute:
    df[attr] = df.country.apply(lambda x: x[attr])
df['country'] = df.country.apply(lambda x: x['country'])

这样做的好处是您只循环使用属性的数量,而不是遍历每个项目。

相关问题