插入DataFrame列并根据PySpark或Pandas中的另一列进行排序

时间:2018-04-27 13:39:52

标签: python pandas apache-spark dataframe pyspark

鉴于以下DataFrame,我们需要从示例中插入my_column值并将它们用作单独的列,然后按降序排列属于每个int_column列的some_id值。例子:

+--------------------+-----------+------------------+
|          some_id   | my_column |      int_column  |
+--------------------+-----------+------------------+
|xx1                 |id_1       |           3      |
|xx1                 |id_2       |           4      |
|xx1                 |id_3       |           5      |
|xx2                 |id_1       |           6      |
|xx2                 |id_2       |           1      |
|xx2                 |id_3       |           3      |
|xx3                 |id_1       |           4      |
|xx3                 |id_2       |           8      |
|xx3                 |id_3       |           9      |
|xx4                 |id_1       |           1      |
+--------------------+-----------+------------------+

预期产出:

+--------------------+-----------+------------------+
|          id_1      | id_2      |      id_3        |
+--------------------+-----------+------------------+
| [xx4, 1]           |[xx2, 1]   |[xx2, 3]          |
| [xx1, 3]           |[xx1, 4]   |[xx1, 5]          |
| [xx3, 4]           |[xx3, 8]   |[xx3, 9]          |
| [xx2, 6]           |null       |null              |
+--------------------+-----------+------------------+

正如您所看到的,对于id_1int_column中的最低数字是1,就在DataFrame的末尾,它属于xx4列中的some_id,下一个值是3,4和6,分别属于xx1,xx3和xx2。

有关如何解决此问题的任何指示?可以使用PySpark或Pandas。

重现输入数据帧的代码:

import pandas as pd

data = {'some_id': ['xx1', 'xx1', 'xx1', 'xx2', 'xx2', 'xx2', 'xx3', 'xx3', 'xx3', 'xx4'], \
        'my_column' : ['id_1', 'id_2', 'id_3', 'id_1', 'id_2', 'id_3', 'id_1', 'id_2', 'id_3', 'id_1'],\
       'int_column' : [3, 4, 5, 6 , 1, 3, 4, 8, 9, 1]}

df = pd.DataFrame.from_dict(data)

2 个答案:

答案 0 :(得分:3)

我们需要一个帮助键,使用cumcount创建,然后我们使用groupby + apply(此部分就像pivot一样,或者您可以使用{{1} }或pivot_table

crosstab

如果使用df=df.assign(key=df.groupby('my_column').cumcount()) df.groupby(['key','my_column']).apply(lambda x : list(zip(x['some_id'],x['int_column']))[0]).unstack() Out[378]: my_column id_1 id_2 id_3 key 0 (xx1, 3) (xx1, 4) (xx1, 5) 1 (xx2, 6) (xx2, 1) (xx2, 3) 2 (xx3, 4) (xx3, 8) (xx3, 9) 3 (xx4, 1) None None + pivot

sort_values

答案 1 :(得分:2)

这是pyspark的解决方案。

首先按my_column定义Window分区,然后按int_column排序。我们将在此分区上使用pyspark.sql.functions.row_number()定义排序。

from pyspark.sql import Window
import pyspark.sql.functions as f
w = Window.partitionBy("my_column").orderBy("int_column")
df.withColumn("order", f.row_number().over(w)).sort("order").show()
#+-------+---------+----------+-----+
#|some_id|my_column|int_column|order|
#+-------+---------+----------+-----+
#|    xx4|     id_1|         1|    1|
#|    xx2|     id_2|         1|    1|
#|    xx2|     id_3|         3|    1|
#|    xx1|     id_2|         4|    2|
#|    xx1|     id_1|         3|    2|
#|    xx1|     id_3|         5|    2|
#|    xx3|     id_2|         8|    3|
#|    xx3|     id_3|         9|    3|
#|    xx3|     id_1|         4|    3|
#|    xx2|     id_1|         6|    4|
#+-------+---------+----------+-----+

请注意(xx4, 1)排在order之后的第一行,正如您所解释的那样。

现在,您可以在order上按pivotmy_column分组数据框。这需要一个聚合函数,因此我将使用pyspark.sql.functions.first(),因为我假设每(some_id, int_column)只有一个order对。然后只需按order排序并删除该列以获得所需的输出:

df.withColumn("order", f.row_number().over(w))\
    .groupBy("order")\
    .pivot("my_column")\
    .agg(f.first(f.array([f.col("some_id"), f.col("int_column")])))\
    .sort("order")\
    .drop("order")\
    .show(truncate=False)
#+--------+--------+--------+
#|id_1    |id_2    |id_3    |
#+--------+--------+--------+
#|[xx4, 1]|[xx2, 1]|[xx2, 3]|
#|[xx1, 3]|[xx1, 4]|[xx1, 5]|
#|[xx3, 4]|[xx3, 8]|[xx3, 9]|
#|[xx2, 6]|null    |null    |
#+--------+--------+--------+