Составьте список из одного ИЛИ множества строковых значений в кадре данных pandas - PullRequest
0 голосов
/ 16 февраля 2019

У меня есть один фрейм данных, полученный в результате пространственного соединения двух объектов Geopandas.GeoDataFrame.

Поскольку было более одного элемента, перекрывающегося с целевым объектом, строки были продублированы, так что каждая строка имеет унаследованную информацию от каждого из перекрывающихся объектов.Чтобы смоделировать эту ситуацию, мы можем запустить следующие строки:

world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
cities = geopandas.read_file(geopandas.datasets.get_path('naturalearth_cities'))

cities = cities[['geometry', 'name']]
cities = cities.rename(columns={'name':'City'})

countries_with_city = geopandas.sjoin(world, cities, how="inner", op='intersects')

Я пытаюсь сгенерировать новый столбец в мировом геофрейме, который содержит список длиной 0,1 или +1, с "City" атрибут всех перекрывающихся городов каждой страны.Для этого я написал следующее:

for country in world.index:
    subset_countries = countries_with_city.loc[countries_with_city.index==world.loc[country, "name"]]
    a = subset_countries["City"].tolist()
    list_of_names = list(subset_countries["City"])
    world[list_of_names]=list_of_names

Однако, когда я запускаю этот код, я застреваю в строке a = subset_countries["City"].tolist().Я получаю ошибку 'str' object has no attribute 'tolist'.

Согласно тому, что я проверил и исследовал, похоже, что я получаю эту ошибку, потому что в первой стране [countries_with_city.loc[countries_with_city.index==world.loc[1, "name"]]] есть только один город.Следовательно, когда я срезаю фрейм данных, то факт, что есть только одна строка с индексом = 1, делает результат строкой, а не фреймом данных, который затем может быть указан в списке.

Есть ли прямой способ, которым я могу использовать, чтобы код работал в любом случае?(когда есть 0, 1 и много городов).Цель состоит в том, чтобы создать список названий городов, которые затем будут записаны в мировом фрейме данных.

Я работаю над Python 3

1 Ответ

0 голосов
/ 16 февраля 2019

Если я правильно вас понимаю, один из подходов состоит в том, чтобы построить отображение из названия страны в список названий городов:

# Build a Series with index=countries, values=cities
country2city = countries_with_city.groupby('name')['City'].agg(lambda x: list(x))

# Use the mapping on the name column of the world DataFrame
world['city_list'] = world['name'].map(county)

# Peek at a nontrivial part of the result
world.drop('geometry', axis=1).tail()
        pop_est continent          name iso_a3  gdp_md_est                                          city_list
172    218519.0   Oceania       Vanuatu    VUT       988.5                                                NaN
173  23822783.0      Asia         Yemen    YEM     55280.0                                            [Sanaa]
174  49052489.0    Africa  South Africa    ZAF    491000.0  [Cape Town, Bloemfontein, Johannesburg, Pretoria]
175  11862740.0    Africa        Zambia    ZMB     17500.0                                           [Lusaka]
176  12619600.0    Africa      Zimbabwe    ZWE      9323.0                                           [Harare]

Если вы собираетесь сразу же распечатать списки городов, вы можете присоединиться кСтроки в каждом списке для удаления квадратных скобок:

world['city_str'] = world['city_list'].apply(lambda x: ', '.join(c for c in x)
                                             if x is not np.nan else None)

# Sanity-check result
world.filter(like='city').tail()
                                             city_list                                         city_str
172                                                NaN                                             None
173                                            [Sanaa]                                            Sanaa
174  [Cape Town, Bloemfontein, Johannesburg, Pretoria]  Cape Town, Bloemfontein, Johannesburg, Pretoria
175                                           [Lusaka]                                           Lusaka
176                                           [Harare]                                           Harare
...