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

#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
  

Он работает последовательно и работает быстрее, чем для цикла.