Вопрос или проблема
Я работаю с набором данных, который измеряет показатели токсичности для разных расовых подгрупп. Я агрегировал данные, чтобы проанализировать среднюю токсичность для каждой расовой подгруппы и сравнил ее со средней токсичностью для всей категории «Раса». Код сейчас выглядит ужасно, и у меня нет сил в данный момент полностью объяснить проект. Моя основная проблема в том, что средняя токсичность для выборок отдельных подгрупп (например, «Черные», «Белые», «Азиаты») значительно ниже средней токсичности для всей популяции этих рас.
Например,
среднее для белых (всего): 0.5366622949663186
среднее для белых (выборка 10%): 0.021136063408190225
среднее для белых (выборка 60%): 0.020211360634081903
Эти средние значения выборок слишком низкие по сравнению с общим средним. Я просто не знаю, почему.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
categories = {
"Сексуальная ориентация": ["лесбиянка", "гей", "бисексуал", "трансгендер", "транс", "квир", "лгбт", "лгбтк", "гомосексуал", "гетеросексуал", "гетеросексуальный"],
"Гендерная идентичность": ["мужчина", "женщина", "небинарный"],
"Раса": ["африканец", "афроамериканец", "черный", "белый", "европеец", "испанец", "латино", "латина", "латинкс", "мексиканец", "азиат", "индиец", "ближневосточный", "китаец", "японец"],
"Национальность": ["канадец", "американец"],
"Религия": ["христианин", "мусульманин", "еврей", "буддист", "католик", "протестант", "сикх", "даосист"],
"Возраст": ["старый", "старше", "молодой", "моложе", "подросток", "миллениал", "средний возраст", "пожилой"],
"Недуг": ["слепой", "глухой", "парализованный"]
}
# Корректная загрузка набора данных
df = pd.read_csv("toxity_per_attribute.csv", dtype=str) # Сначала читаем все как строки
# Преобразование TOXICITY в формат float
df["TOXICITY"] = pd.to_numeric(df["TOXICITY"], errors="coerce")
# Удаление строк, где TOXICITY больше 1 (для исправления проблем с несовпадением)
df = df[df["TOXICITY"] <= 1]
# Преобразование столбцов подгрупп из строк "TRUE"/"FALSE" в фактические булевые значения
subgroup_cols = df.columns[2:] # Все столбцы, кроме Wiki_ID и TOXICITY
df[subgroup_cols] = df[subgroup_cols].replace({"TRUE": True, "FALSE": False})
# Шаг 3.1: Удаление строк, в которых все значения подгрупп равны False
df_filtered = df.copy()
df_filtered["subgroup_sum"] = df_filtered[subgroup_cols].sum(axis=1) # Обеспечиваем числовую сумму
df_filtered = df_filtered[df_filtered["subgroup_sum"] > 0] # Оставляем строки, где хотя бы одна подгруппа равна True
df_filtered.drop(columns=["subgroup_sum"], inplace=True)
# Шаг 2: Классификация подгрупп в Защищенные классы
protected_classes = categories
def combine_subgroups(df, class_dict):
for class_name, subgroups in class_dict.items():
df[class_name] = df[subgroups].max(axis=1) # Обеспечение присутствия
combine_subgroups(df_filtered, protected_classes)
# Шаг 3: Убедитесь, что значения подгрупп остаются 0 или 1
df_filtered[subgroup_cols] = df_filtered[subgroup_cols].replace({True: 1, False: 0})
# Шаг 4: Вычисление корреляции между Защищенными классами и токсичностью
correlations = {}
for class_name in protected_classes.keys():
filtered_df = df_filtered[[class_name, "TOXICITY"]].dropna()
if filtered_df[class_name].nunique() > 1:
correlations[class_name] = filtered_df[class_name].corr(filtered_df['TOXICITY'])
else:
correlations[class_name] = 0
correlation_table = pd.DataFrame({
'Защищенный класс': correlations.keys(),
'Корреляция': correlations.values()
})
print("Обновленная таблица корреляций:")
print(correlation_table)
# Шаг 5: Статистический анализ
mean_toxicity = df_filtered['TOXICITY'].mean()
std_toxicity = df_filtered['TOXICITY'].std()
confidence_interval = (
max(0, mean_toxicity - 1.96 * std_toxicity),
min(1, mean_toxicity + 1.96 * std_toxicity)
)
print(f"Средняя токсичность: {mean_toxicity}, Стандартное отклонение: {std_toxicity}, 95%-ный интервал: {confidence_interval}")
# Шаг 6: Анализ подгрупп для выбранного защищенного класса
chosen_class = "Раса"
subgroup_means = {}
for subgroup in categories[chosen_class]:
if subgroup in df_filtered.columns:
mean_value = df_filtered[df_filtered[subgroup] > 0]["TOXICITY"].mean()
print(f"Средняя токсичность для {subgroup}: {mean_value}")
subgroup_means[subgroup] = mean_value
else:
print(f"Предупреждение: {subgroup} не найден в df_filtered")
subgroup_means[subgroup] = None
print(f"Средние значения токсичности для подгрупп {chosen_class}:", subgroup_means)
# Шаг 7: Визуализация Boxplot для 3 лучших корреляций
top_correlations = correlation_table.nlargest(3, 'Корреляция')
for class_name in top_correlations["Защищенный класс"]:
plt.figure(figsize=(8, 6))
sns.boxplot(x=df_filtered[class_name], y=df_filtered["TOXICITY"])
plt.xlabel(class_name)
plt.ylabel("Токсичность")
plt.title(f"Распределение токсичности по {class_name}")
plt.show()
# Шаг 8: Анализ случайной выборки для выбранного защищенного класса
def random_sample_analysis(df, sample_size, column):
sample = df.sample(frac=sample_size, random_state=42)
mean_sample = sample[column].mean()
std_sample = sample[column].std()
margin_of_error = 1.96 * (std_sample / np.sqrt(len(sample)))
return mean_sample, std_sample, margin_of_error
sample_10 = random_sample_analysis(df_filtered, 0.1, "Раса")
sample_60 = random_sample_analysis(df_filtered, 0.6, "Раса")
print(f"10% Выборка (Раса): Среднее = {sample_10[0]}, Станд. отклонение = {sample_10[1]}, Погрешность = {sample_10[2]}")
print(f"60% Выборка (Раса): Среднее = {sample_60[0]}, Станд. отклонение = {sample_60[1]}, Погрешность = {sample_60[2]}")
# Шаг 8.1: Случайная выборка для подгрупп в выбранном защищенном классе
for subgroup in categories[chosen_class]:
if subgroup in df_filtered.columns:
sample_10 = random_sample_analysis(df_filtered, 0.1, subgroup)
sample_60 = random_sample_analysis(df_filtered, 0.6, subgroup)
print(f"10% Выборка ({subgroup}): Среднее = {sample_10[0]}, Станд. отклонение = {sample_10[1]}, Погрешность = {sample_10[2]}")
print(f"60% Выборка ({subgroup}): Среднее = {sample_60[0]}, Станд. отклонение = {sample_60[1]}, Погрешность = {sample_60[2]}")
sns.histplot(df_filtered["TOXICITY"], bins=20, kde=True)
plt.xlabel("Токсичность")
plt.ylabel("Частота")
plt.title("Распределение токсичности в полном наборе данных")
plt.show()
for subgroup in categories["Раса"]:
if subgroup in df_filtered.columns:
sample_10 = df_filtered.sample(frac=0.1, random_state=42)
sample_60 = df_filtered.sample(frac=0.6, random_state=42)
# Проверьте, сколько строк действительно имеют для подгруппы значение True
print(f"{subgroup}: {sample_10[sample_10[subgroup] > 0].shape[0]} / {sample_10.shape[0]} строк в выборке 10%")
print(f"{subgroup}: {sample_60[sample_60[subgroup] > 0].shape[0]} / {sample_60.shape[0]} строк в выборке 60%")
Я попробовал это:
for subgroup in categories[chosen_class]:
if subgroup in df_filtered.columns:
sample_10 = random_sample_analysis(df_filtered, 0.1, subgroup)
sample_60 = random_sample_analysis(df_filtered, 0.6, subgroup)
print(f"10% Выборка ({subgroup}): Среднее = {sample_10[0]}, Станд. отклонение = {sample_10[1]}, Погрешность = {sample_10[2]}")
print(f"60% Выборка ({subgroup}): Среднее = {sample_60[0]}, Станд. отклонение = {sample_60[1]}, Погрешность = {sample_60[2]}")
Которое, как я думал, сработает, но оно все еще дает мне средние значения выборок, которые слишком низки по сравнению с средними значениями всей популяции.
Ответ или решение
Понимание того, почему средняя токсичность отдельных расовых подгрупп ниже средней токсичности для всей категории "Расы", требует комплексного подхода, связанного как с теоретическими аспектами статистического анализа, так и с практическими примерами и их приложением.
Теория
Первоначально рассмотрим теоретический аспект проблемы. Когда мы анализируем набор данных с точки зрения подгрупп, мы фактически применяем процесс выборки, который может привести к различиям в статистических показателях. Основная причина такой разницы может заключаться в смещении выборки. Смещение выборки происходит, когда выбранная выборка не является репрезентативной для всей генеральной совокупности. В случае вашего набора данных, среднее значение токсичности для подгрупп может быть искажено из-за меньшей величины выборки или из-за специфического распределения значений, характерного для этой подгруппы.
Другой аспект — это влияние редких событий. Если в генеральной совокупности наблюдается большое количество высокотоксичных случаев, а в подгруппе — нет, это также может привести к ниже средней токсичности в подгруппе по сравнению с общей категорией.
Пример
Для иллюстрации этого предположим, что в вашей выборке для категории "Белые" содержится несколько записей с очень высоким уровнем токсичности, таких как 0.9 или даже выше. Эти значения могут существенно влиять на общее среднее в то время как при случайной выборке из подгруппы такие значения могут и не попасть в выборку.
Приложение
Практически вы можете изучить следующие подходы, чтобы понять и, возможно, исправить эту диспропорцию:
-
Проверка репрезентативности. Убедитесь, что выборка из подгруппы действительно репрезентативна для всей подгруппы. Это может включать применение стратифицированной выборки, где учитывается распределение ключевых показателей в подгруппе.
-
Анализ редких событий. Проверьте распределение токсичности в генеральной совокупности и выясните, возможно ли наличие экстремальных значений, которые вносят вклад в увеличение общей средней.
-
Исключение аномалий. Рассмотрите возможность исключения аномальных значений или применения методов стабилизации, таких как логарифмическое преобразование.
-
Проверка на полноту и качество данных. Проверьте, нет ли в данных ошибок или пропущенных значений, которые могут повлиять на анализ.
-
Увеличение размера выборки. Попробуйте увеличить размер выборки, чтобы исследовать, приводит ли это к изменению средней токсичности для подгруппы ближе к общей средней.
-
Глубокий анализ данных. Выполните более детальный анализ подгрупп, включая проверку корреляций и взаимосвязей разных подкатегорий и токсичности.
Заключение
Ваш анализ средних показателей токсичности подсказывает существование потенциальных проблем с выборкой и распределением данных. Эти проблемы часто встречаются в аналитике данных и требуют тщательной проверки и анализа. Применение перечисленных выше стратегий может помочь улучшить понимание вашего набора данных и предоставить более точные результаты, соответствующие различным демографическим характеристикам анализируемых подгрупп.