#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