Я учусь обрабатывать пропущенные значения в наборе данных. У меня есть таблица с ~ 1 миллионом записей. Я пытаюсь справиться с небольшим количеством пропущенных значений.
Мои данные касаются системы проката велосипедов, а недостающие значения — это начальное и конечное местоположения.
Данные: отсутствуют начальные станции, всего 7 значений
Данные: отсутствует конечная станция, всего 24 значения
Хочу заполнить NaN
в обоих случаях режимом "встречной" станции. Например, для start_station==21
я хочу увидеть, что является наиболее распространенным end_station
, и использовать это, чтобы заполнить мое отсутствующее значение.
Например. df.loc[df['start_station'] == 21].end_station.mode()
Я попытался добиться этого с помощью функции:
def inpute_end_station(df):
for index, row in df.iterrows():
if pd.isnull(df.loc[index, 'end_station']):
start_st = df.loc[index, 'start_station']
mode = df.loc[df['start_station'] == start_st].end_station.mode()
df.loc[index, 'end_station'].fillna(mode, inplace=True)
В последней строке выбрасывается AttributeError: 'numpy.float64' object has no attribute 'fillna'
. Если вместо этого я просто использую df.loc[index, 'end_station'] = mode
, я получаю ValueError: Incompatible indexer with Series
.
Правильно ли я подхожу к этому? Я понимаю, что изменять что-то, что вы повторяете, в пандах — плохая практика, так как же правильно изменить столбцы start_station
и end_station
и заменить NaN
соответствующим режимом дополнительной станции?
@ALollz решение работает с вспомогательной функцией, но я получаю SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead
. Это действительно лучший способ?
Эта ошибка, вероятно, не связана с этим и связана с предыдущей операцией среза, которая создала копию. Вы можете прочитать это для получения дополнительной информации в stackoverflow.com/questions/20625582/…, но временное исправление TLDR заключается в том, что вам, вероятно, следует просто выполнить df = df.copy()
до того, какая строка кода выдаст это предупреждение. На самом деле вам следует зафиксировать операцию среза в другом месте, что, вероятно, потребует .copy()
после некоторого шага маскирования или переписать код без цепочечного присваивания.
На мой взгляд, когда вы хотите перебирать столбец в пандах, как это, лучше всего использовать функцию apply()
.
Для этого конкретного случая я бы предложил следующий подход, который показан ниже на моем образце данных. У меня нет большого опыта использования метода mode()
, поэтому я использовал метод value_counts()
в сочетании с методом first_valid_index()
для определения значения моды.
# import pandas
import pandas as pd
# make a sample data
list_of_rows = [
{'start_station': 1, 'end_station': 1},
{'start_station': None, 'end_station': 1},
{'start_station': 1, 'end_station': 2},
{'start_station': 1, 'end_station': 3},
{'start_station': 2, 'end_station': None},
{'start_station': 2, 'end_station': 3},
{'start_station': 2, 'end_station': 3},
]
# make a pandas data frame
df = pd.DataFrame(list_of_rows)
# define a function
def fill_NaNs_in_end_station(row):
if pd.isnull(row['end_station']):
start_station = row['start_station']
return df[df['start_station']==start_station].end_station.value_counts().first_valid_index()
return row['end_station']
# apply function to dataframe
df['end_station'] = df.apply(lambda row: fill_NaNs_in_end_station(row), axis=1)
Похоже на этот вопрос, заданный вчера: stackoverflow.com/questions/55562696/…. Должна быть возможность использовать ту же функцию (только с другими именами столбцов), а затем отображать результат.