Подтвердить что ты не робот

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, называемая "индексирование", которая запугивает меня, потому что я плохо ее понимаю. Если индексирование является важной частью решения этой проблемы, пожалуйста, опустите ваше объяснение индексации.

4b9b3361

Ответ 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. Мы управляем этим в течение всех лет ваших временных рядов.