У меня есть искровой фрейм данных, как показано ниже

df = pd.DataFrame({
'subject_id':[1,1,1,1,2,2,2,2,3,3,4,4,4,4,4],
'readings' : ['READ_1','READ_2','READ_1','READ_3',np.nan,'READ_5',np.nan,'READ_8','READ_10','READ_12','READ_11','READ_14','READ_09','READ_08','READ_07'],
 'val' :[5,np.nan,7,np.nan,np.nan,7,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,46],
 })

from pyspark.sql.types import *
from pyspark.sql.functions import isnan, when, count, col

mySchema = StructType([ StructField("subject_id", LongType(), True)\
                       ,StructField("readings", StringType(), True)\
                       ,StructField("val", FloatType(), True)])

spark_df = spark.createDataFrame(df,schema=mySchema)

Что я хочу сделать, так это удалить столбцы, которые содержат более 80% значений NaN, NULL or 0?

Я пробовал что-то вроде ниже, но это не работает

spark_df = spark_df.dropna(axis = 'columns',how=any,thresh=12)

Вышеупомянутое возможно в pandas, но здесь не работает. Я получаю ошибку ниже, и это не удивительно

TypeError: dropna () получил неожиданный аргумент ключевого слова 'axis'

Обратите внимание, что мой настоящий фрейм данных - 40 million and 3k columns. Я сослался на эту запись но на него еще нет ответа

Есть ли что-нибудь подобное в pyspark?

Я ожидаю, что мой результат будет таким, как показано ниже, всего с двумя столбцами.

enter image description here

3
The Great 29 Окт 2019 в 10:14

2 ответа

Вы можете напрямую использовать эту функцию, она самая быстрая из возможных:

def drop_null_columns_spark(df, threshold=0):
    """
    This function drops all columns which contain null values with a threshold.
    :param df: A PySpark DataFrame
    :param threshold: Minimum number of nulls to consider dropping of column
    """
    null_counts = df.select([F.count(F.when(F.col(c).isNull(), c)).alias(c) for c in df.columns]).collect()[0].asDict()
    to_drop = [k for k, v in null_counts.items() if v > threshold]
    df = df.drop(*to_drop)
    return df
1
pissall 31 Окт 2019 в 08:15
Спасибо постараюсь. Проголосовали. Но я уже пробовал подобную оценку. Разве это не займет больше времени, например, для 1300 столбцов?
 – 
The Great
9 Ноя 2019 в 13:23
Подсчет - дорогостоящая операция, но она необходима, потому что вам нужен правильный счетчик NULL. Сбор стоит недорого, потому что вы объединены в одну строку.
 – 
pissall
9 Ноя 2019 в 13:29

Вы можете использовать параметр subset в методе dropna, чтобы указать столбцы, в которых будут отображаться нулевые значения.

Чтобы удалить все столбцы с более чем 80% нулевых значений:

columns_to_drop = []
count_before = spark_df.count()

for column_name in spark_df.columns:
    temp_spark_df =  spark_df.dropna(subset=[column_name], how=any, thresh=12)
    count_after = temp_spark_df.count()

    if ((count_before-count_after)/count_before) > 0.8:
        columns_to_drop.append(column_name)


spark_df = spark_df.drop(*columns_to_drop)

1
Rithin Chalumuri 29 Окт 2019 в 11:02
Спасибо постараюсь. Но, к сожалению, мой фреймворк действительно огромен - до 40 миллионов и 3k столбцов. Вот и думаю, будет ли быстро. В любом случае проголосовали за. Постараюсь скоро обновить ответ. Спасибо
 – 
The Great
29 Окт 2019 в 11:04