Выбор подмножества кадра данных с каждой переменной, имеющей данные за N лет - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть набор данных, показывающий годовые показатели роста для более чем 100 стран, с 1970 по 2013 год. Не во всех странах есть данные за все годы, в стране с наименьшим количеством лет есть данные за 30 лет.Я хочу выровнять вещи и сделать так, чтобы все страны показывали мне данные за 30 лет, удаляя годы из стран, в которых> 30.Я приведу пример ниже.

Я думал об использовании циклов для удаления данных из кадра данных до тех пор, пока все страны не появятся 30 раз, а затем для создания целого нового кадра данных, но мне нравится верить, что есть лучшее решение.

import pandas as pd

data = {'Country':['Israel','Congo','Denmark',
                   'Israel','Denmark',
                   'Israel','Congo',
                   'Israel','Congo','Denmark'],
        'Year':[2000,2000,2000,
                2001,2001,
                2002,2002,
                2003,2003,2003],
        'Value':[2.5,1.2,3.1,2.8,1.1,2.9,3.1,1.9,3.0,3.1]}
df = pd.DataFrame(data=data)
df
   Country  Year  Value
0   Israel  2000    2.5
1    Congo  2000    1.2
2  Denmark  2000    3.1
3   Israel  2001    2.8
4  Denmark  2001    1.1
5   Israel  2002    2.9
6    Congo  2002    3.1
7   Israel  2003    1.9
8    Congo  2003    3.0
9  Denmark  2003    3.1

Приведенный выше код создает фрейм данных с примером, использующим всего 3 страны и 4 года.Из таблицы данных видно, что у Израиля есть данные за 4 года, а у Дании и Конго - только три.Я хочу удалить год из Израиля, чтобы у всех стран было 3 года.В реальном кадре данных я хочу удалить годы из стран, в которых более 30 лет, чтобы во всех странах были одинаковые годы, предпочтительно удалить год с наименьшим значением.

Вот мое решение, использующее для циклов, которое используетмного строк кода:

gp = df.groupby('Country').groups #Group by country name
d = {} #Build dictionary Country Name => index list.

for i in gp: #Iterate over all countries until a list of 3 indeces is 
#reached for each country.
    d[i] = []
    for j in gp[i]:
        if len(d[i])<3: #A country appears once every year in the dataset,
#3 means 3 years. If a country appears more than 3 times, it will only 
#include the indices of the first 3 occurrences. 
            d[i].append(j)
indeces = [] #Gather the indeces to keep in the dataframe.
for i in d:
    for j in d[i]:
        if len(d[i])==3: #make sure the list has exactly 3 items
            indeces.append(j)

final_df = df.loc[indeces,['Country','Year','Value']]
final_df
#Now I have one less value for Israel, so all countries have 3 values.
   Country  Year  Value
1    Congo  2000    1.2
6    Congo  2002    3.1
8    Congo  2003    3.0
2  Denmark  2000    3.1
4  Denmark  2001    1.1
9  Denmark  2003    3.1
0   Israel  2000    2.5
3   Israel  2001    2.8
5   Israel  2002    2.9

Ответы [ 2 ]

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

Это мое решение с использованием панд.Он сделал то, что должен был сделать, хотя он использует много строк кода.Спасибо @Vaishali за помощь:

threshold = 3 #Anything that occurs less than this will be removed, 
              #if it ocurrs more, the extra ocurrences with the least values 
              #will be removed.
newIndex = df.set_index('Country')#set new index to make selection by   
                                  #index posible.
values = newIndex.index.value_counts() #Count occurrences of index values.
to_keep = values[values>=threshold].index.values 
#Keep index values that ocurr >= threshold.
rank_df = newIndex.loc[to_keep,['Value','Year']]#Select rows and  
                                                #columns to keep.

#Sort values in descending order before meeting threshold.
rank_df = rank_df.sort_values('Value',ascending=False)
rank_df = rank_df.groupby(rank_df.index).head(threshold)#group again 
#Since values are sorted, head() will show highest values
rank_df = rank_df.groupby([rank_df.index,'Year']).mean() \
              .sort_values('Value',ascending=False)

#Finally, reset index to convert Year index into a column, and sort by year
rank_df.reset_index(level=1).sort_values('Year')

Вывод:

            Year    Value
Country         
Denmark     2000    3.1
Israel      2000    2.5
Congo       2000    1.2
Israel      2001    2.8
Denmark     2001    1.1
Congo       2002    3.1
Israel      2002    2.9
Denmark     2003    3.1
Congo       2003    3.0
0 голосов
/ 08 февраля 2019

Вы можете создать список последних лет из столбца уникальных значений в году и использовать логическое индексирование для индексации фрейма данных, используя этот список.

recent_years = df.Year.unique()[-3:]
df[df.Year.isin(recent_years)]

    Country Year    Value
3   Israel  2001    2.8
4   Denmark 2001    1.1
5   Israel  2002    2.9
6   Congo   2002    3.1
7   Israel  2003    1.9
8   Congo   2003    3.0
9   Denmark 2003    3.1

Если значения года не обязательно в порядке, используйте numpyunique, который возвращает отсортированный массив в отличие от pandas unique ()

recent_years = np.unique(df.Year)[-3:]
df[df.Year.isin(recent_years)]

Вот еще одно решение, которое возвращает 3 последних года для каждой страны.Если данные не отсортированы по году, они должны быть отсортированы в первую очередь.

idx = df.groupby('Country').apply(lambda x: x['Year'].tail(3)).index
df.set_index(['Country', df.index]).reindex(idx).reset_index().drop('level_1', 1)

    Country Year    Value
0   Congo   2000    1.2
1   Congo   2002    3.1
2   Congo   2003    3.0
3   Denmark 2000    3.1
4   Denmark 2001    1.1
5   Denmark 2003    3.1
6   Israel  2001    2.8
7   Israel  2002    2.9
8   Israel  2003    1.9

Если данные не отсортированы, сначала отсортируйте их, используя

df = df.sort_values(by = 'Year')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...