我有来自CSV(gist with small sample)的pandas DataFrame:
| title | genres |
--------------------------------------------------------
| %title1% |[{id: 1, name: '...'}, {id: 2, name: '...'}]|
| %title2% |[{id: 2, name: '...'}, {id: 4, name: '...'}]|
...
| %title9% |[{id: 3, name: '...'}, {id: 9, name: '...'}]|
每个title
都可以与各种类型的流派(大于或大于1)相关联。
任务是将genre
列中的数组转换为列,并为每种流派放置一个(或True
s):
| title | genre_1 | genre_2 | genre_3 | ... | genre_9 |
---------------------------------------------------------
| %title1% | 1 | 1 | 0 | ... | 0 |
| %title2% | 1 | 0 | 0 | ... | 0 |
...
| %title9% | 0 | 0 | 1 | ... | 1 |
流派是常量集(该集中的约20个项目)。
天真的方法是:
genres
列中,并用1填充该类型的列。这种方法看起来有点奇怪。
我认为大熊猫有一种更合适的方法。
答案 0 :(得分:0)
据我所知,没有办法以矢量化方式对Pandas数据帧执行JSON反序列化。您应该能够执行此操作的一种方法是使用.iterrows()
,它可以让您在一个循环中执行此操作(尽管比大多数内置的熊猫操作要慢)。
import json
df = # ... your dataframe
for index, row in df.iterrows():
# deserialize the JSON string
json_data = json.loads(row['genres'])
# add a new column for each of the genres (Pandas is okay with it being sparse)
for genre in json_data:
df.loc[index, genre['name']] = 1 # update the row in the df itself
df.drop(['genres'], axis=1, inplace=True)
请注意,用NaN
而不是0填充的空白单元格–您应使用.fillna()
进行更改。带有近似相似数据框的简短示例如下
In [1]: import pandas as pd
In [2]: df = pd.DataFrame([{'title': 'hello', 'json': '{"foo": "bar"}'}, {'title': 'world', 'json': '{"foo": "bar", "ba
...: z": "boo"}'}])
In [3]: df.head()
Out[3]:
json title
0 {"foo": "bar"} hello
1 {"foo": "bar", "baz": "boo"} world
In [4]: import json
...: for index, row in df.iterrows():
...: data = json.loads(row['json'])
...: for k, v in data.items():
...: df.loc[index, k] = v
...: df.drop(['json'], axis=1, inplace=True)
In [5]: df.head()
Out[5]:
title foo baz
0 hello bar NaN
1 world bar boo
答案 1 :(得分:0)
如果您的csv数据如下所示。
(我将引号添加到流派json的键中只是为了轻松使用json包。由于这不是主要问题,您可以将其作为预处理来处理)
您将不得不遍历输入DataFrame的所有行。
for index, row in inputDf.iterrows():
fullDataFrame = pd.concat([fullDataFrame, get_dataframe_for_a_row(row)])
在get_dataframe_for_a_row函数中:
,然后为每行构建一个DataFrame并将它们连接到完整的DataFrame。 pd.concat()连接从每一行获得的数据帧。 如果已经存在,将合并这些公社。
最后,fullDataFrame.fillna(0)
将NaN替换为0
这是完整的代码:
import pandas as pd
import json
inputDf = pd.read_csv('title_genre.csv')
def labels_for_genre(a):
a[0]['id']
labels = []
for i in range(0 , len(a)):
label = 'genre'+'_'+str(a[i]['id'])
labels.append(label)
return labels
def get_dataframe_for_a_row(row):
labels = labels_for_genre(json.loads(row['genres']))
tempDf = pd.DataFrame()
tempDf['title'] = [row['title']]
for label in labels:
tempDf[label] = ['1']
return tempDf
fullDataFrame = pd.DataFrame()
for index, row in inputDf.iterrows():
fullDataFrame = pd.concat([fullDataFrame, get_dataframe_for_a_row(row)])
fullDataFrame = fullDataFrame.fillna(0)
答案 2 :(得分:0)
没有iterrows
的完整解决方案:
import pandas as pd
import itertools
import json
# read data
movies_df = pd.read_csv('https://gist.githubusercontent.com/feeeper/9c7b1e8f8a4cc262f17675ef0f6e1124/raw/022c0d45c660970ca55e889cd763ce37a54cc73b/example.csv', converters={ 'genres': json.loads })
# get genres for all items
all_genres_entries = list(itertools.chain.from_iterable(movies_df['genres'].values))
# create the list with unique genres
genres = list({v['id']:v for v in all_genres_entries}.values())
# fill genres columns
for genre in genres:
movies_df['genre_{}'.format(genre['id'])] = movies_df['genres'].apply(lambda x: 1 if genre in x else 0)