파이썬 pandas 데이터프레임의 특정 컬럼을 주어진 두개의 시리즈로 채워넣기

조회수 691회

이미지

데이터프레임2개와 시리즈2개가 있습니다. 원하는것을 df2에 금액란을 원하는값으로 채워넣고 싶습니다. 과일id를 기준으로 '금액'을 1순위로 넣고 과일id가 공란이면 원산지평균액을 넣어주는 내용입니다. 말은 쉬운데 구현이 어렵네요.

2 답변

  • 재밌을 것 같아서 해 봤습니다.

    pandas 에서는 series, dataframe 에 index 라는 것이 있는데, index 가 딕셔너리의 key와 같은 개념으로 생각할 때 편리할 수가 있습니다. 이 질문의 예가 바로 그렇습니다. 그저 단순히 df[column] = series 로 세팅하면, 마치 dict.update 와 같이 동작합니다.

    예제코드를 잘 보시고 이해해 보시기 바랍니다.

    import numpy as np
    import pandas as pd
    
    df1 = pd.DataFrame(
        {
            "과일명": ["사과", "토마토", "바나나", "포도"],
            "과일id": [0, 1, 2, 3],
            "금액": [600, 700, 300, 400],
            "원산지": ["서울", "서울", "제주", "대전"],
            "원산지평균액": [800, 800, 200, 500],
        }
    )
    df2 = pd.DataFrame(
        {
            "과일명": ["사과", "바나나", "거봉"],
            "과일id": [0, 2, 4],
            "원산지": ["서울", "제주", "대전"],
            "금액": [np.NaN, np.NaN, np.NaN],
            "원하는값": [600, 300, 500],
        }
    )
    s1 = pd.Series([600, 700, 300, 400], index=["사과", "토마토", "바나나", "포도"])
    s2 = pd.Series([800, 200, 500], index=["서울", "제주", "대전"])
    
    colums_org = df2.columns
    
    df2 = df2.set_index("과일명")
    df2["금액"] = s1
    df2 = df2.reset_index()
    
    print(df2.to_markdown())
    """
    |    | 과일명   |   과일id | 원산지   |   금액 |   원하는값 |
    |---:|:---------|---------:|:---------|-------:|-----------:|
    |  0 | 사과     |        0 | 서울     |    600 |        600 |
    |  1 | 바나나   |        2 | 제주     |    300 |        300 |
    |  2 | 거봉     |        4 | 대전     |    nan |        500 |
    """
    
    df2 = df2.set_index("원산지")
    df2.loc[df2["금액"].isna(), "금액"] = s2
    df2 = df2.reset_index()
    
    print(df2.to_markdown())
    """
    |    | 원산지   | 과일명   |   과일id |   금액 |   원하는값 |
    |---:|:---------|:---------|---------:|-------:|-----------:|
    |  0 | 서울     | 사과     |        0 |    600 |        600 |
    |  1 | 제주     | 바나나   |        2 |    300 |        300 |
    |  2 | 대전     | 거봉     |        4 |    500 |        500 |
    """
    
    df2 = df2[colums_org]
    print(df2.to_markdown())
    """
    |    | 과일명   |   과일id | 원산지   |   금액 |   원하는값 |
    |---:|:---------|---------:|:---------|-------:|-----------:|
    |  0 | 사과     |        0 | 서울     |    600 |        600 |
    |  1 | 바나나   |        2 | 제주     |    300 |        300 |
    |  2 | 거봉     |        4 | 대전     |    500 |        500 |
    """
    
    • 추가 : 마지막에 컬럼순서 바꾸는 코드가 잘못되어서 수정함.
  • 요컨대 문제 상황은

    • 과일별로 값이 알려져 있고
    • 원산지별로 과일 값이 보통 얼마쯤 된다는 정보가 있고
    • 어느 과일이 어느 원산지에서 값이 얼마라는 정보가 일부 있어서
    • 그런 정보가 없는 과일+원산지 조합의 값은 '원산지별 과일값 대충 얼마' 정보로 갈음해야 된다는

    뭐 그런 상황이 맞는 거죠?
    만약 그렇다면, 제가 데이터프레임을 잘 몰라서 SQL로 해봤는데, 아닌 게 아니라 실제로도 좀 까다로운 면이 있는 것 같습니다.

    select
      total.item_name,
      total.area_name,
      ifnull(some.price, total.default_price) AS possible_price -- 이 부분이 magic. some에서 찾아봐서 없으면 total을 쓴다
    from (
      select
        items.id AS item_id,
        items.name As item_name,
        areas.id AS area_id,
        areas.name AS area_name,
        areas.default_value AS default_price
      from items, areas -- 가능한 모든 경우의 수를 조합한다
    ) as total -- 가능한 모든 경우 각각에 '이미 알려져 있는 과일+원산지 정보를 추가로 붙인다
    left join item_area_prices some -- 이 테이블이 df1에 해당함
      ON some.item_id = total.item_id AND some.area_id = total.area_id -- 두 조건 모두 만족해야 함
    order by total.item_id, total.area_id;
    

    참고가 되면 좋겠네요.

    • 상황은 정확히 맞습니다 ㅎㅎㅎ 알 수 없는 사용자 2021.12.2 21:50
    • 글쿤요 다음에는 그런 배경상황을 적어주시면 다른분들이 답변 달 때 추리하는 시간을 절약할 수 있겠지요. 아무튼 핵심 아이디어는 series1 x series2 모든 경우의 수를 나열한 다음 거기에 df1을 매칭해본다는 것인데 이걸 df로 어떻게 하는지는 다른 분이 답변 주실 거 같네요. 엽토군 2021.12.2 21:53

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)