Среднее значение динамического подмножества столбцов на основе строк в Панд

#python #pandas #list #dataframe #numpy

Вопрос:

У меня есть проблема, которую можно визуализировать следующим образом:

Наш Кошка То Главная Они Способный
Алиса 10 15 NaN 30 20 25
Боб 12 NaN 14 29 NaN 30
Джон NaN 9 NaN NaN NaN 20
Тайлер 11 12 13 24 25 26

Как правило, каждому человеку (индексу) в каждом столбце присваиваются числовые данные (индекс), но есть пустые места. Мне интересно, как заполнить каждый NaN средним значением для одного и того же человека для столбцов с той же длиной имени, что и столбец с отсутствующим значением. Другими словами, как объединить fillna() и mean() с некоторой пользовательской логикой, для которой учитываются столбцы. Идеальным результатом было бы:

Наш Кошка То Главная Они Способный
Алиса 10 15 12.5 30 20 25
Боб 12 13 14 29 29.5 30
Джон 9 9 9 20 20 20
Тайлер 11 12 13 24 25 26

При этом цифры, выделенные жирным шрифтом, являются средними значениями для одного и того же человека для одной и той же «длины столбца».

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

Заранее спасибо за всю помощь.

Ответ №1:

вы можете попробовать:

 df = df.groupby(df.columns.map(len), axis =1).apply(lambda x: x.T.fillna(x.mean(1)).T)
 

выход:

         Our   Cat   The  Home  They  Able
Alice  10.0  15.0  12.5  30.0  20.0  25.0
Bob    12.0  13.0  14.0  29.0  29.5  30.0
John    9.0   9.0   9.0  20.0  20.0  20.0
Tyler  11.0  12.0  13.0  24.0  25.0  26.0
 

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

1. Я не сторонник отказа, но я думаю, что вы неправильно истолковываете вопрос. Операция хочет заполнить нулевые значения сгруппированным средним значением, основанным на длине символа имени столбца. Например, длина Кошки Нашей собаки равна 3, поэтому сгруппированное среднее значение равно 9 (для этих столбцов). Аналогично, другие столбцы имеют длину 4, поэтому сгруппированное среднее значение должно основываться на них, чтобы заполнить нули в этих столбцах.

2. @софокл О, да!!. ты прав!!. Я неправильно понял вопрос. Спасибо 🙂 Постараюсь исправить ответ.

3. Это, кажется, намного быстрее, чем мой ответ с большим объемом данных; отлично сделано! 1

Ответ №2:

Похоже, это работает:

 # create a df to hold the per-person means for each column name length
meandf = pd.DataFrame(index=df.index, columns=df.columns, dtype=float)

# find the unique column name lengths
lengths = set(len(i) for i in df.columns)

# iterate over the lengths and find take the mean for that chunk of the df
for l in lengths:
    subsetcols = df.columns[[len(col) == l for col in df.columns]]
    personmeans = df.loc[:, subsetcols].mean(axis=1)
    meandf.loc[personmeans.index, subsetcols] = personmeans

# write to the original df
df[df.isna()] = meandf
 

Результат:

 >>> df
        Our   Cat   The  Home  They  Able
Alice  10.0  15.0  12.5  30.0  20.0    25
Bob    12.0  13.0  14.0  29.0  29.5    30
John    9.0   9.0   9.0  20.0  20.0    20
Tyler  11.0  12.0  13.0  24.0  25.0    26
 

Я использовал meandf в качестве промежуточной структуры для хранения средств (без этого я не мог понять индексацию). В каждой ячейке содержится среднее значение для каждого человека для каждой длины имени столбца:

 >>> meandf
        Our   Cat   The  Home  They  Able
Alice  12.5  12.5  12.5  25.0  25.0  25.0
Bob    13.0  13.0  13.0  29.5  29.5  29.5
John    9.0   9.0   9.0  20.0  20.0  20.0
Tyler  12.0  12.0  12.0  25.0  25.0  25.0