Извлечь данные из столбца DataFrame формата словаря
В столбце 'production countries' (pandas.DataFrame) датасета 'data' все данные выглядят подобным образом: [{"iso_3166_1": "IN", "name": "India"}] и имеют тип object. Необходимо переделать подобные строки в 'India' (для этого примера). В общем случае шаблон выглядит так: [{"iso_3166_1": "XX", "name": "COUNTRY"}] надо переделать в "COUNTRY" для всего столбца в датасете. К тому же в столбце есть такие значения [], их надо игнорировать. Пробовала создать функцию по типу такого:
def extract_country(row):
if row==[]:
return row
else:
import json
return lambda row: json.loads(row)['name']
data['production countries'] = data['production countries'].apply(extract_country)
но в таком случае в столбец добавляются значения <function extract_country.<locals>.<lambda> at...
Ещё была попытка воспользоваться помощью gpt:
def extract_country_name(country):
country_dict = eval(country) # преобразуем строку в словарь
if isinstance(country_dict, list) and len(country_dict) > 0: # проверяем, что это список и он не пустой
country_name = country_dict[0].get('name') # извлекаем название страны из словаря
if country_name: # проверяем, что название страны не пустое
return country_name
return country # если что-то пошло не так, возвращаем исходное значение
data['countries'] = data['countries'].apply(extract_country_name)
Но в этом случае возникает ошибка при выводе
Ответы (5 шт):
Не обязательно писать такую большую функцию, вот вариант с помощью лямбда функции:
df['production countries'] = df['production countries'].apply(lambda x: x if x == [] else x[0]['name'])
Если я правильно понял, когда строка-пустой список-ее не меняем, когда строка-список с одним элементом в виде словаря, то берем значение ключа name в этом словаре.
Решение нашлось:
def extract_country(json_string):
# Преобразование строки JSON в список Python
country_list = json.loads(json_string)
# Проверка на []
if len(country_list) > 0:
# Извлечение названия страны из первого элемента списка
country_dict = country_list[0]
country_name = country_dict['name']
return country_name
else:
return []
# Применение функции extract_country к столбцу 'production countries'
data['production countries'] = data['production countries'].apply(extract_country)
Теперь всё работает как нужно: столбец заполняется извлечёнными названиями стран
Для случая, когда в ячейках содержится не просто словарь, а список словарей с одинаковыми ключами и нужно выбрать оттуда все значения с ключом 'name':
def extract_names(json_string):
new_list = json.loads(json_string) # преобразование строки JSON в список Python
# проверка наличия элементов в списке
if len(new_list) > 0:
list_of_dicts=[]
# извлечение необходимых названий из всех словарей списка
for i in range(len(new_list)):
list_of_dicts.append(new_list[i])
list_of_names = [country_dict['name'] for country_dict in list_of_dicts]
return list_of_names
else:
return []
Это можно сделать с помощью pandas.Series.str.get, в короткой записи .str[]:
data = pd.Series([[{"iso_3166_1": "IN", "name": "India"}], [], [{"iso_3166_1": "CN", "name": "China"}]]).to_frame().rename(columns={0: 'production countries'})
print('\nИсходный фрейм\n', data)
mask = ~data['production countries'].str[0].isna() # создаем булев массив для обработки только тех строк, где непустой список
data.loc[mask,'production countries'] = data.loc[mask,'production countries'].str[0].str['name'] # выделяем сначала нулевой элемент списка (словарь), потом из словаря - значение по ключу
print('\nРезультат\n', data)
Исходный фрейм
production countries
0 [{'iso_3166_1': 'IN', 'name': 'India'}]
1 []
2 [{'iso_3166_1': 'CN', 'name': 'China'}]
Результат
production countries
0 India
1 []
2 China
Можно все векторизовать в довольно компактный код:
дано:
import pandas as pd
df = pd.DataFrame({"country":[[{"iso_3166_1": "IN", "name": "India"}],
[{"iso_3166_2": "RU", "name": "Russia"}],
[],
[{"iso_3166_2": "EC", "name": "Ecuador"}]]})
country
0 [{'iso_3166_1': 'IN', 'name': 'India'}]
1 [{'iso_3166_2': 'RU', 'name': 'Russia'}]
2 []
3 [{'iso_3166_2': 'EC', 'name': 'Ecuador'}]
решение:
df["country"] = df["country"].str[0].fillna('').apply(lambda x: x.get("name") if x else [])
получаем df:
country
0 India
1 Russia
2 []
3 Ecuador
Делаем из столбца своего рода датафрейм, прибавляем его в обозначенные до "равно" столбцы
data[['iso', 'Country']] = data['production countries'].apply(pd.Series)