Spark Dataframe은 중복 된 이름으로 열을 구별합니다.


82

따라서 Spark Dataframe에서 알 수 있듯이 여러 열의 경우 아래 데이터 프레임 스냅 샷에 표시된 것과 동일한 이름을 가질 수 있습니다.

[
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=125231, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0047, 3: 0.0, 4: 0.0043})),
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=145831, f=SparseVector(5, {0: 0.0, 1: 0.2356, 2: 0.0036, 3: 0.0, 4: 0.4132})),
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=147031, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=149231, f=SparseVector(5, {0: 0.0, 1: 0.0032, 2: 0.2451, 3: 0.0, 4: 0.0042}))
]

위의 결과는 데이터 프레임과 결합하여 생성되며 4두 개의 af.

문제는 내가 더 많은 계산을하려고 할 때이된다 a열, 나는를 선택하는 방법을 찾을 수 없습니다 a, 나는 시도했다 df[0]df.select('a')모두 오류 mesaage 아래 나를 돌아 :

AnalysisException: Reference 'a' is ambiguous, could be: a#1333L, a#1335L.

어쨌든 Spark API에 중복 된 이름과 열을 다시 구별 할 수있는 것이 있습니까? 아니면 열 이름을 변경할 수있는 방법이 있습니까?

답변:


61

.NET Framework의 열 이름을 변경하는 것이 좋습니다 join.

df1.select(col("a") as "df1_a", col("f") as "df1_f")
   .join(df2.select(col("a") as "df2_a", col("f") as "df2_f"), col("df1_a" === col("df2_a"))

결과 DataFrameschema

(df1_a, df1_f, df2_a, df2_f)

5
열 이름 사이에 따옴표가 제대로 조정되지 않았기 때문에 답변을 수정해야 할 수도 있습니다.
Sameh Sharaf

2
@SamehSharaf 나는 당신이 내 대답에 투표 한 사람이라고 생각합니까? 그러나 대답은 사실 100 % 정확합니다. 저는 단순히 '열 선택을 위해 scala -shorthand를 사용하고 있기 때문에 실제로 따옴표에 문제가 없습니다.
Glennie Helles Sindholt

31
@GlennieHellesSindholt, 공정한 포인트. 대답이 python및 로 태그되어 있기 때문에 혼란 스럽습니다 pyspark.
Jorge Leitao 2018

각 데이터 프레임에 100 개 이상의 열이 포함되어 있고 동일한 열 이름 하나만 변경하면 어떻게 될까요? 확실히 select 절에있는 모든 열 이름을 수동으로 입력 할 수는 없습니다
bikashg

6
이 경우 함께 갈 수 있습니다df1.withColumnRenamed("a", "df1_a")
Glennie Helles Sindholt

100

몇 가지 데이터부터 시작하겠습니다.

from pyspark.mllib.linalg import SparseVector
from pyspark.sql import Row

df1 = sqlContext.createDataFrame([
    Row(a=107831, f=SparseVector(
        5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
    Row(a=125231, f=SparseVector(
        5, {0: 0.0, 1: 0.0, 2: 0.0047, 3: 0.0, 4: 0.0043})),
])

df2 = sqlContext.createDataFrame([
    Row(a=107831, f=SparseVector(
        5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
    Row(a=107831, f=SparseVector(
        5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
])

이 문제에 접근 할 수있는 몇 가지 방법이 있습니다. 우선 부모 열을 사용하여 자식 테이블 열을 명확하게 참조 할 수 있습니다.

df1.join(df2, df1['a'] == df2['a']).select(df1['f']).show(2)

##  +--------------------+
##  |                   f|
##  +--------------------+
##  |(5,[0,1,2,3,4],[0...|
##  |(5,[0,1,2,3,4],[0...|
##  +--------------------+

테이블 별칭을 사용할 수도 있습니다.

from pyspark.sql.functions import col

df1_a = df1.alias("df1_a")
df2_a = df2.alias("df2_a")

df1_a.join(df2_a, col('df1_a.a') == col('df2_a.a')).select('df1_a.f').show(2)

##  +--------------------+
##  |                   f|
##  +--------------------+
##  |(5,[0,1,2,3,4],[0...|
##  |(5,[0,1,2,3,4],[0...|
##  +--------------------+

마지막으로 프로그래밍 방식으로 열 이름을 바꿀 수 있습니다.

df1_r = df1.select(*(col(x).alias(x + '_df1') for x in df1.columns))
df2_r = df2.select(*(col(x).alias(x + '_df2') for x in df2.columns))

df1_r.join(df2_r, col('a_df1') == col('a_df2')).select(col('f_df1')).show(2)

## +--------------------+
## |               f_df1|
## +--------------------+
## |(5,[0,1,2,3,4],[0...|
## |(5,[0,1,2,3,4],[0...|
## +--------------------+

7
모호한 경우에 올바른 열을 얻는 여러 가지 방법을 보여준 편집에 감사드립니다. 귀하의 예제가 Spark 프로그래밍 가이드에 포함되어야한다고 생각합니다. 많이 배웠어요!
resec

작은 수정 : df2_r = **df2** .select(*(col(x).alias(x + '_df2') for x in df2.columns))대신 df2_r = df1.select(*(col(x).alias(x + '_df2') for x in df2.columns)). 나머지, 좋은 물건
Vzzarr

나는 이것이 Spark 프로그래밍 가이드의 일부 여야한다는 데 동의합니다. 순금. 조인을하기 전에 이전 이름으로 열을 선택하는 모호성의 원인을 마침내 풀 수있었습니다. 모든 모호성을 제거하기 전에 열 이름에 프로그래밍 방식으로 접미사를 추가하는 솔루션입니다.
Pablo Adames

26

다음을 수행하여 결합하는 모든 열에 대한 별칭을 작성하는 것보다 더 간단한 방법이 있습니다.

df1.join(df2,['a'])

이것은 조인하는 키가 두 테이블에서 동일 할 경우 작동합니다.

참조 https://kb.databricks.com/data/join-two-dataframes-duplicated-columns.html를


4
이 2+ 불꽃의 같은 실제 답변입니다
매트

2
그리고 Scala의 경우 : df1.join (df2, Seq ( "a"))
mauriciojost

1
페이지로 이동되었습니다 kb.databricks.com/data/...
bogdan.rusu

7

def drop(col: Column)방법을 사용 하여 복제 된 열을 삭제할 수 있습니다 . 예를 들면 다음과 같습니다.

DataFrame:df1

+-------+-----+
| a     | f   |
+-------+-----+
|107831 | ... |
|107831 | ... |
+-------+-----+

DataFrame:df2

+-------+-----+
| a     | f   |
+-------+-----+
|107831 | ... |
|107831 | ... |
+-------+-----+

df1과 df2를 결합하면 DataFrame은 다음과 같습니다.

val newDf = df1.join(df2,df1("a")===df2("a"))

DataFrame:newDf

+-------+-----+-------+-----+
| a     | f   | a     | f   |
+-------+-----+-------+-----+
|107831 | ... |107831 | ... |
|107831 | ... |107831 | ... |
+-------+-----+-------+-----+

이제 def drop(col: Column)다음과 같이 메서드를 사용 하여 복제 된 열 'a'또는 'f'를 삭제할 수 있습니다 .

val newDfWithoutDuplicate = df1.join(df2,df1("a")===df2("a")).drop(df2("a")).drop(df2("f"))

외부 조인을 수행하고 두 열에 다른 값이있는 경우이 방법이 작동합니까?
prafi

동일한 스키마와 다른 관계가 있으면 삭제하지 않을 수 있습니다.
thebluephantom 20:08에

5

Spark API를 alias살펴본 후 먼저 원래 데이터 프레임에 대한 별칭을 생성하는 데 사용할 수 있음을 발견 한 다음 withColumnRenamed별칭의 모든 열의 이름을 수동으로 바꾸는 데 사용할 수 있습니다. 이렇게하면 join열 이름이 중복되지 않습니다.

자세한 내용은 아래 Spark Dataframe API를 참조하십시오 .

pyspark.sql.DataFrame.alias

pyspark.sql.DataFrame.withColumnRenamed

그러나 이것은 번거로운 해결 방법 일뿐이며 내 질문에 더 좋은 방법이 있는지 궁금합니다.


4

이것이 PySpark 에서 동일한 열 이름에 있는 두 개의 Dataframe 결합하는 방법 입니다.

df = df1.join(df2, ['col1','col2','col3'])

당신이 할 경우 printSchema()이 후 당신은 중복 된 열이 제거 된 것을 볼 수 있습니다.


3

조인하려는 DataFrame이 df1 및 df2이고 열 'a'에 조인한다고 가정하면 두 가지 방법이 있습니다.

방법 1

df1.join (df2, 'a', 'left_outer')

이것은 끔찍한 방법이며 적극 권장됩니다.

방법 2

df1.join (df2, df1.a == df2.a, 'left_outer'). drop (df2.a)


1

이것이 최선의 방법이 아닐 수도 있지만 중복 열의 이름을 바꾸고 싶다면 (조인 후)이 작은 함수를 사용하여 그렇게 할 수 있습니다.

def rename_duplicate_columns(dataframe):
    columns = dataframe.columns
    duplicate_column_indices = list(set([columns.index(col) for col in columns if columns.count(col) == 2]))
    for index in duplicate_column_indices:
        columns[index] = columns[index]+'2'
    dataframe = dataframe.toDF(*columns)
    return dataframe

1

두 테이블에서 키 열만 동일하면 다음 방법을 사용해보십시오 (접근법 1).

left. join(right , 'key', 'inner')

아래보다는 (접근 2) :

left. join(right , left.key == right.key, 'inner')

접근 방식 1의 장점 :

  • '키'는 최종 데이터 프레임에서 한 번만 표시됩니다.
  • 사용하기 쉬운 구문

접근 방식 1 사용의 단점 :

  • 키 열에 만 도움이
  • 왼쪽 조인의 경우 오른쪽 키 null 개수를 사용하려는 경우이 기능이 작동하지 않습니다. 이 경우 위에서 언급 한대로 키 중 하나의 이름을 바꿔야합니다.

0

Glennie Helles Sindholt의 답변에 설명 된 것보다 더 복잡한 사용 사례가있는 경우, 예를 들어 동일한 비조 인 열 이름이 몇 개 있고 동일한 이름을 선택하는 동안 구분하려는 경우 별칭을 사용하는 것이 가장 좋습니다. 예 :

df3 = df1.select("a", "b").alias("left")\
   .join(df2.select("a", "b").alias("right"), ["a"])\
   .select("left.a", "left.b", "right.b")

df3.columns
['a', 'b', 'b']
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.