Pandas - Вычислить z-балл для всех столбцов
У меня есть фреймворк, содержащий один столбец идентификаторов, а все остальные столбцы - это числовые значения, для которых я хочу вычислить z-баллы. Вот его подраздел:
ID Age BMI Risk Factor
PT 6 48 19.3 4
PT 8 43 20.9 NaN
PT 2 39 18.1 3
PT 9 41 19.5 NaN
Некоторые из моих столбцов содержат значения NaN, которые я не хочу включать в вычисления z-score, поэтому я намерен использовать решение, предлагаемое для этого вопроса: как zscore normalize pandas с nans?
df['zscore'] = (df.a - df.a.mean())/df.a.std(ddof=0)
Я заинтересован в применении этого решения ко всем моим столбцам, кроме столбца ID, чтобы создать новый фреймворк данных, который можно сохранить в виде файла Excel, используя
df2.to_excel("Z-Scores.xlsx")
Итак, в основном; как я могу вычислить z-баллы для каждого столбца (игнорируя значения NaN) и выталкивать все в новый фреймворк?
SIDENOTE: существует концепция в pandas, называемая "индексирование", которая запугивает меня, потому что я плохо ее понимаю. Если индексирование является важной частью решения этой проблемы, пожалуйста, опустите ваше объяснение индексации.
Ответы
Ответ 1
Создайте список из столбцов и удалите столбец, который вы не хотите рассчитывать для оценки Z:
In [66]:
cols = list(df.columns)
cols.remove('ID')
df[cols]
Out[66]:
Age BMI Risk Factor
0 6 48 19.3 4
1 8 43 20.9 NaN
2 2 39 18.1 3
3 9 41 19.5 NaN
In [68]:
# now iterate over the remaining columns and create a new zscore column
for col in cols:
col_zscore = col + '_zscore'
df[col_zscore] = (df[col] - df[col].mean())/df[col].std(ddof=0)
df
Out[68]:
ID Age BMI Risk Factor Age_zscore BMI_zscore Risk_zscore \
0 PT 6 48 19.3 4 -0.093250 1.569614 -0.150946
1 PT 8 43 20.9 NaN 0.652753 0.074744 1.459148
2 PT 2 39 18.1 3 -1.585258 -1.121153 -1.358517
3 PT 9 41 19.5 NaN 1.025755 -0.523205 0.050315
Factor_zscore
0 1
1 NaN
2 -1
3 NaN
Ответ 2
Использование Функция Scipy zscore:
df = pd.DataFrame(np.random.randint(100, 200, size=(5, 3)), columns=['A', 'B', 'C'])
df
| | A | B | C |
|---:|----:|----:|----:|
| 0 | 163 | 163 | 159 |
| 1 | 120 | 153 | 181 |
| 2 | 130 | 199 | 108 |
| 3 | 108 | 188 | 157 |
| 4 | 109 | 171 | 119 |
from scipy.stats import zscore
df.apply(zscore)
| | A | B | C |
|---:|----------:|----------:|----------:|
| 0 | 1.83447 | -0.708023 | 0.523362 |
| 1 | -0.297482 | -1.30804 | 1.3342 |
| 2 | 0.198321 | 1.45205 | -1.35632 |
| 3 | -0.892446 | 0.792025 | 0.449649 |
| 4 | -0.842866 | -0.228007 | -0.950897 |
Если не все столбцы вашего фрейма данных являются числовыми, то вы можете применить функцию Z-score только к числовым столбцам с помощью функции select_dtypes
:
# Note that `select_dtypes` returns a data frame. We are selecting only the columns
numeric_cols = df.select_dtypes(include=[np.number]).columns
df[numeric_cols].apply(zscore)
| | A | B | C |
|---:|----------:|----------:|----------:|
| 0 | 1.83447 | -0.708023 | 0.523362 |
| 1 | -0.297482 | -1.30804 | 1.3342 |
| 2 | 0.198321 | 1.45205 | -1.35632 |
| 3 | -0.892446 | 0.792025 | 0.449649 |
| 4 | -0.842866 | -0.228007 | -0.950897 |
Ответ 3
Почти однострочное решение:
df2 = (df.ix[:,1:] - df.ix[:,1:].mean()) / df.ix[:,1:].std()
df2['ID'] = df['ID']
Ответ 4
Если вы хотите рассчитать zscore для всех столбцов, вы можете просто использовать следующее:
df_zscore = (df - df.mean())/df.std()
Ответ 5
Когда мы имеем дело с временными рядами, вычисление z-баллов (или аномалий - не одно и то же, но вы можете легко адаптировать этот код) - немного сложнее. Например, у вас есть 10 лет данных о температуре, измеренных еженедельно. Чтобы рассчитать z-баллы для всего временного ряда, вы должны знать средства и стандартные отклонения для каждого дня года. Итак, давайте начнем:
Предположим, что у вас есть pandas DataFrame. Прежде всего, вам нужен индекс DateTime. Если у вас его еще нет, но, к счастью, у вас есть столбец с датами, просто сделайте это как ваш индекс. pandas попытается угадать формат даты. Цель здесь - иметь DateTimeIndex. Вы можете проверить это, попробовав:
type(df.index)
Если у вас его нет, сделайте это.
df.index = pd.DatetimeIndex(df[datecolumn])
df = df.drop(datecolumn,axis=1)
Следующий шаг - рассчитать среднее и стандартное отклонение для каждой группы дней. Для этого мы используем метод groupby.
mean = pd.groupby(df,by=[df.index.dayofyear]).aggregate(np.nanmean)
std = pd.groupby(df,by=[df.index.dayofyear]).aggregate(np.nanstd)
Наконец, мы перебираем все даты, выполняя вычисление (value-mean)/stddev; однако, как уже упоминалось, для временных рядов это не так просто.
df2 = df.copy() #keep a copy for future comparisons
for y in np.unique(df.index.year):
for d in np.unique(df.index.dayofyear):
df2[(df.index.year==y) & (df.index.dayofyear==d)] = (df[(df.index.year==y) & (df.index.dayofyear==d)]- mean.ix[d])/std.ix[d]
df2.index.name = 'date' #this is just to look nicer
df2 #this is your z-score dataset.
Логика внутри циклов for: для данного года мы должны сопоставлять каждый день с его средним значением и stdev. Мы управляем этим в течение всех лет ваших временных рядов.