Обрезка столбцов фрейма данных с использованием совпадающих длин подмножества столбцов

#python #pandas

#python #pandas

Вопрос:

У меня есть фрейм данных, который содержит годовые данные с нескольких сайтов. На каждом сайте существует несколько источников данных, которые не все имеют одинаковую длину в годах. Я не знаю верхнюю и нижнюю границы лет заранее, и они разные для каждого сайта.

Мои данные выглядят следующим образом:

 Year    Site    Source    Value
1880     1         A       1.2
1881     1         A       1.4
1882     1         A       2.1
1883     1         A       2.7
1881     1         B       1.3
1882     1         B       1.8
1883     1         B       1.4
1891     2         A       1.9
1892     2         A       2.0
1893     2         A       2.1
1892     2         B       2.4
1893     2         B       2.2
  

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

 Year    Site    Source    Value
1881     1         A       1.4
1882     1         A       2.1
1883     1         A       2.7
1881     1         B       1.3
1882     1         B       1.8
1883     1         B       1.4
1892     2         A       2.0
1893     2         A       2.1
1892     2         B       2.4
1893     2         B       2.2  
  

Моя попытка до сих пор:

 for site in df['Site'].unique():

    A = df[df['Source'] == 'A']
    B = df[df['Source'] == 'B']

    if len(A['Year']) < len(B['Year']):
        B['Year'] = B.clip(A['Year'].min, A.['Year'].max)

    if len(B['Year']) < len(A['Year'):
        A['Year'] = A.clip(B['Year'].min, B['Year'].max)

    df[df['Source'] == 'A'] = A
    B = df[df['Source'] == 'B']
  

Создает:

 Year    Site    Source    Value
1881     1         A       1.4
1882     1         A       2.1
1883     1         A       2.7
1881     1         B       1.3
1882     1         B       1.8
1883     1         B       1.4
1881     2         A       1.4
1882     2         A       2.1
1883     2         A       2.7
1881     2         B       1.3
1882     2         B       1.8
1883     2         B       1.4  
  

Ответ №1:

Поскольку сайты независимы, с ними можно работать с помощью функции в groupby, сравнимой с вашим внешним циклом.

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

 def filter_site(site):
    # look at the lowest year for each source,
    # take the max value of them as lower bound
    lower = site.groupby("Source").Year.min().max()

    # likewise for upper bound
    upper = site.groupby("Source").Year.max().min()

    # filter with lower and upper bound
    return site[(site.Year >= lower) amp; (site.Year <= upper)]
  

А затем примените функцию ко всем сайтам:

 df.groupby("Site", group_keys=False).apply(filter_site)
  

Комментарии:

1. Кажется, что это должно сработать, но когда я выполняю проверку, печатая столбец «Длина года» для каждого источника по сайтам, я все еще получаю разные длины. Если бы это работало правильно, я бы получал одинаковую длину для каждого источника по сайтам.

2. Возможно ли, что в данных есть разрывы, между нижней и верхней границами отсутствуют годы?

3. Нет. У меня есть строка над этой реализацией, которая удаляет любые 0 / пропущенные значения. И проверка с использованием df.info () для каждого сайта и источника не показывает никаких нулевых значений

4. Я имел в виду, что диапазоны могут быть не непрерывными. Например, на сайте / источнике может быть 1881, 1883, 1884 (отсутствует 1882). Тогда длины могут не совпадать.

5. Возвращаюсь, чтобы принять ваш ответ. Обнаружена ошибка, не связанная с вашим кодом. Исправлено, и теперь ваше решение работает идеально.