#python #pandas #loops #statistics
#python #pandas #циклы #Статистика
Вопрос:
Я следую курсу Datacamp по «эффективному управлению данными» на pandas. В своих видеороликах, в качестве примера, они демонстрируют собственный метод перебора фрейма данных для вычисления zscore.
Я нашел этот конкретный курс странным из-за того, что кажется ошибками в коде, и мне интересно, было ли это сделано для более старой версии Python, но, скорее всего, я просто не понимаю.
Фрейм данных в основном выглядит примерно так:
df = pd.DataFrame({'total_bill': {0: 16.99, 1: 10.34, 2: 21.01, 3: 23.68, 4: 24.59, 5: 25.29, 6: 8.77, 7: 26.88, 8: 15.04, 9: 14.78}, 'tip': {0: 1.01, 1: 1.66, 2: 3.5, 3: 3.31, 4: 3.61, 5: 4.71, 6: 2.0, 7: 3.12, 8: 1.96, 9: 3.23}, 'sex': {0: 'Female', 1: 'Male', 2: 'Male', 3: 'Male', 4: 'Female', 5: 'Male', 6: 'Male', 7: 'Male', 8: 'Male', 9: 'Male'}, 'smoker': {0: 'No', 1: 'No', 2: 'No', 3: 'No', 4: 'No', 5: 'No', 6: 'No', 7: 'No', 8: 'No', 9: 'No'}, 'day': {0: 'Sun', 1: 'Sun', 2: 'Sun', 3: 'Sun', 4: 'Sun', 5: 'Sun', 6: 'Sun', 7: 'Sun', 8: 'Sun', 9: 'Sun'}, 'time': {0: 'Dinner', 1: 'Dinner', 2: 'Dinner', 3: 'Dinner', 4: 'Dinner', 5: 'Dinner', 6: 'Dinner', 7: 'Dinner', 8: 'Dinner', 9: 'Dinner'}, 'size': {0: 2, 1: 3, 2: 3, 3: 2, 4: 4, 5: 4, 6: 2, 7: 4, 8: 2, 9: 2}})
Итак, код на слайдах выглядит следующим образом:
mean_female = df.groupby("sex").mean()["total_bill"]["Female"]
mean_male = df.groupby("sex").mean()["total_bill"]["Male"]
std_female = df.groupby("sex").std()["total_bill"]["Female"]
std_male = df.groupby("sex").std()["total_bill"]["Male"]
Далее следует это…
for i in range(len(df)):
if df.iloc[i,2] == "Female":
df.iloc[i][0] = (df.iloc[i,0] - mean_female) / std_female
else:
df.iloc[i][0] = (df.iloc[i,0] - mean_male) / std_male
Когда я запускаю код (который из datacamp, а не мой) Я получаю обычную копию предупреждения о фрагменте, но (что более важно) с фреймом данных НИЧЕГО не происходит.
Я предполагаю, что цель состоит в том, чтобы иметь что-то вроде этого:
zscore = lambda x: (x - x.mean()) / x.std()
dfsex = restaurant.groupby('sex')
dfzscore = grouptime["total_bill"].transform(zscore)
dfzscore
Я немного смущен, поэтому любая помощь в этом очень ценится.
Приветствия!
Ответ №1:
.iloc[i,0]
следует использовать вместо .iloc[i][0]
. Фрейм данных будет правильно обновлен после исправления этой ошибки. Доказательства:
df
Out[58]:
total_bill tip sex smoker day time size
0 -0.707107 1.01 Female No Sun Dinner 2
1 -1.138059 1.66 Male No Sun Dinner 3
2 0.402209 3.50 Male No Sun Dinner 3
3 0.787637 3.31 Male No Sun Dinner 2
4 0.707107 3.61 Female No Sun Dinner 4
5 1.020048 4.71 Male No Sun Dinner 4
6 -1.364696 2.00 Male No Sun Dinner 2
7 1.249573 3.12 Male No Sun Dinner 4
8 -0.459590 1.96 Male No Sun Dinner 2
9 -0.497122 3.23 Male No Sun Dinner 2
Объяснение: Давайте внимательно рассмотрим df.iloc[i][0]
. Первый шаг df.iloc[i]
действительно возвращает ряд на месте. Однако второй шаг [0]
просто возвращает копию значения, которого нет на месте. Поэтому df
не будет обновляться.
Короче говоря, каждый индекс должен быть помещен внутрь .iloc[]
(или, возможно, лучше .iat[]
в этом случае), чтобы присвоение значения происходило на месте.
Комментарии:
1. Спасибо, первым, что я попробовал, был ввод iloc [i,0], но, очевидно, я не сделал это правильно! Должен был проверить мой код перед запуском StackOverflow!!
Ответ №2:
используйте:
df.assign(column0_name= lambda x: np.where(x['column2_name']=='Female',
(x['column0_name'] - mean_female) / std_female),
(x['column0_name'] - mean_male) / std_male)))
Вместо:
for i in range(len(df)):
if df.iloc[i,2] == "Female":
df.iloc[i][0] = (df.iloc[i,0] - mean_female) / std_female
else:
df.iloc[i][0] = (df.iloc[i,0] - mean_male) / std_male
Он работает последовательно и работает быстрее, чем для цикла.