ไม่รู้สึกเฉพาะส่วนของคอลัมน์จาก pandas dataframe


9

ฉันมีตัวอย่าง dataframe ต่อไปนี้:

df = pd.DataFrame(data = {'RecordID' : [1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5], 'DisplayLabel' : ['Source','Test','Value 1','Value 2','Value3','Source','Test','Value 1','Value 2','Source','Test','Value 1','Value 2','Source','Test','Value 1','Value 2','Source','Test','Value 1','Value 2'],
'Value' : ['Web','Logic','S','I','Complete','Person','Voice','>20','P','Mail','OCR','A','I','Dictation','Understandable','S','I','Web','Logic','R','S']})

ซึ่งสร้าง DataFrame นี้:

+-------+----------+---------------+----------------+
| Index | RecordID | Display Label |     Value      |
+-------+----------+---------------+----------------+
|     0 |        1 | Source        | Web            |
|     1 |        1 | Test          | Logic          |
|     2 |        1 | Value 1       | S              |
|     3 |        1 | Value 2       | I              |
|     4 |        1 | Value 3       | Complete       |
|     5 |        2 | Source        | Person         |
|     6 |        2 | Test          | Voice          |
|     7 |        2 | Value 1       | >20            |
|     8 |        2 | Value 2       | P              |
|     9 |        3 | Source        | Mail           |
|    10 |        3 | Test          | OCR            |
|    11 |        3 | Value 1       | A              |
|    12 |        3 | Value 2       | I              |
|    13 |        4 | Source        | Dictation      |
|    14 |        4 | Test          | Understandable |
|    15 |        4 | Value 1       | S              |
|    16 |        4 | Value 2       | I              |
|    17 |        5 | Source        | Web            |
|    18 |        5 | Test          | Logic          |
|    19 |        5 | Value 1       | R              |
|    20 |        5 | Value 2       | S              |
+-------+----------+---------------+----------------+

ฉันพยายามที่จะ "unmelt" แม้ว่าจะไม่ตรงกับที่มาและทดสอบคอลัมน์ในคอลัมน์ dataframe ใหม่ซึ่งจะมีลักษณะเช่นนี้:

+-------+----------+-----------+----------------+---------------+----------+
| Index | RecordID |  Source   |      Test      | Result        |  Value   |
+-------+----------+-----------+----------------+---------------+----------+
|     0 |        1 | Web       | Logic          | Value 1       | S        |
|     1 |        1 | Web       | Logic          | Value 2       | I        |
|     2 |        1 | Web       | Logic          | Value 3       | Complete |
|     3 |        2 | Person    | Voice          | Value 1       | >20      |
|     4 |        2 | Person    | Voice          | Value 2       | P        |
|     5 |        3 | Mail      | OCR            | Value 1       | A        |
|     6 |        3 | Mail      | OCR            | Value 2       | I        |
|     7 |        4 | Dictation | Understandable | Value 1       | S        |
|     8 |        4 | Dictation | Understandable | Value 2       | I        |
|     9 |        5 | Web       | Logic          | Value 1       | R        |
|    10 |        5 | Web       | Logic          | Value 2       | S        |
+-------+----------+-----------+----------------+---------------+----------+

ฉันเข้าใจว่าการหมุนและการหลอมจะทำคอลัมน์ DisplayLabel ทั้งหมดและไม่ใช่แค่ค่าบางอย่าง

ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมากเมื่อฉันได้อ่านPandas MeltและPandas Pivot รวมถึงการอ้างอิงบางส่วนเกี่ยวกับ stackoverflow และฉันไม่สามารถหาวิธีที่จะทำสิ่งนี้ได้อย่างรวดเร็ว

ขอบคุณ!


คุณจะรู้ได้อย่างไรว่าผลการทดสอบใน DataFrame ดั้งเดิมของคุณเชื่อมโยงกับอะไร ตัวอย่างเช่นในดัชนี 2 คุณจะรู้ได้อย่างไรว่าValue 1อยู่ภายใต้Logicแถวทดสอบใน DataFrame ที่สองของคุณ
Nathan Clement

สวัสดีนาธาน! ฉันทำผิดพลาดในตารางสุดท้ายเนื่องจากกลุ่มข้อมูลบันทึกรวมกลุ่มของแหล่งข้อมูลและค่าทั้งหมดเข้าด้วยกัน ขอโทษ.
Jon

คำตอบ:


6

เราสามารถบรรลุผลของคุณโดยใช้ตรรกะและการหมุนรอบเราแบ่งข้อมูลของคุณโดยการตรวจสอบว่าDisplayLabelมีValueและจากนั้นjoinพวกเรากลับมารวมกัน:

mask = df['DisplayLabel'].str.contains('Value')
df2 = df[~mask].pivot(index='RecordID', columns='DisplayLabel', values='Value')

dfpiv = (
    df[mask].rename(columns={'DisplayLabel':'Result'})
            .set_index('RecordID')
            .join(df2)
            .reset_index()
)
    RecordID   Result     Value     Source            Test
0          1  Value 1         S        Web           Logic
1          1  Value 2         I        Web           Logic
2          1   Value3  Complete        Web           Logic
3          2  Value 1       >20     Person           Voice
4          2  Value 2         P     Person           Voice
5          3  Value 1         A       Mail             OCR
6          3  Value 2         I       Mail             OCR
7          4  Value 1         S  Dictation  Understandable
8          4  Value 2         I  Dictation  Understandable
9          5  Value 1         R        Web           Logic
10         5  Value 2         S        Web           Logic

หากคุณต้องการลำดับคอลัมน์ที่แน่นอนเป็นตัวอย่างของคุณใช้DataFrame.reindex:

dfpiv.reindex(columns=['RecordID', 'Source', 'Test', 'Result', 'Value'])

    RecordID     Source            Test   Result     Value
0          1        Web           Logic  Value 1         S
1          1        Web           Logic  Value 2         I
2          1        Web           Logic   Value3  Complete
3          2     Person           Voice  Value 1       >20
4          2     Person           Voice  Value 2         P
5          3       Mail             OCR  Value 1         A
6          3       Mail             OCR  Value 2         I
7          4  Dictation  Understandable  Value 1         S
8          4  Dictation  Understandable  Value 2         I
9          5        Web           Logic  Value 1         R
10         5        Web           Logic  Value 2         S

ในรายละเอียด - ทีละขั้นตอน:

# mask all rows where "Value" is in column DisplayLabel
mask = df['DisplayLabel'].str.contains('Value')

0     False
1     False
2      True
3      True
4      True
5     False
6     False
7      True
8      True
9     False
10    False
11     True
12     True
13    False
14    False
15     True
16     True
17    False
18    False
19     True
20     True
Name: DisplayLabel, dtype: bool
# select all rows which do NOT have "Value" in DisplayLabel
df[~mask]

    RecordID DisplayLabel           Value
0          1       Source             Web
1          1         Test           Logic
5          2       Source          Person
6          2         Test           Voice
9          3       Source            Mail
10         3         Test             OCR
13         4       Source       Dictation
14         4         Test  Understandable
17         5       Source             Web
18         5         Test           Logic
# pivot the values in DisplayLabel to columns
df2 = df[~mask].pivot(index='RecordID', columns='DisplayLabel', values='Value')

DisplayLabel     Source            Test
RecordID                               
1                   Web           Logic
2                Person           Voice
3                  Mail             OCR
4             Dictation  Understandable
5                   Web           Logic
df[mask].rename(columns={'DisplayLabel':'Result'}) # rename the column DisplayLabel to Result
            .set_index('RecordID')                 # set RecordId as index so we can join df2 
            .join(df2)                             # join df2 back to our dataframe based RecordId
            .reset_index()                         # reset index so we get RecordId back as column

    RecordID   Result     Value     Source            Test
0          1  Value 1         S        Web           Logic
1          1  Value 2         I        Web           Logic
2          1   Value3  Complete        Web           Logic
3          2  Value 1       >20     Person           Voice
4          2  Value 2         P     Person           Voice
5          3  Value 1         A       Mail             OCR
6          3  Value 2         I       Mail             OCR
7          4  Value 1         S  Dictation  Understandable
8          4  Value 2         I  Dictation  Understandable
9          5  Value 1         R        Web           Logic
10         5  Value 2         S        Web           Logic

คุณช่วยอธิบายรายละเอียดขั้นตอนของคุณได้ไหม? ฉันคิดว่าฉันติดตาม แต่สำหรับฉันและคนอื่น ๆ ใน StackOverflow มันอาจมีประโยชน์มาก โดยเฉพาะถ้าคุณมีคอลัมน์มากขึ้นคุณจะแก้ไขมันอย่างไร ขอบคุณมากสำหรับการแก้ปัญหา!
จอน

แน่นอนฉันเห็นการแก้ไขฉันเขียนคำอธิบายโดยละเอียดอย่างละเอียด หวังว่านี่จะช่วย
@Jon

ขอบคุณ @Erfan มาก ๆ ! ฉันพบข้อผิดพลาดแปลก ๆ เมื่อฉันไปถึงขั้นตอนการหมุนฉันยังคงได้รับสิ่งนี้: ดัชนีมีรายการที่ซ้ำกันไม่สามารถเปลี่ยนรูปร่างได้ ความคิดใด ๆ
จอน

6

set_index, unstackแล้วmelt

df.set_index(['RecordID', 'DisplayLabel']).Value.unstack().reset_index() \
  .melt(['RecordID', 'Source', 'Test'], var_name='Result', value_name='Value') \
  .sort_values('RecordID').dropna(subset=['Value'])

    RecordID     Source            Test   Result     Value
0          1        Web           Logic  Value 1         S
5          1        Web           Logic  Value 2         I
10         1        Web           Logic  Value 3  Complete
1          2     Person           Voice  Value 1       >20
6          2     Person           Voice  Value 2         P
2          3       Mail             OCR  Value 1         A
7          3       Mail             OCR  Value 2         I
3          4  Dictation  Understandable  Value 1         S
8          4  Dictation  Understandable  Value 2         I
4          5        Web           Logic  Value 1         R
9          5        Web           Logic  Value 2         S

ฟังก์ชั่นที่กำหนดเองสำหรับ groupby

def f(t):
    name, df = t
    d = dict(zip(df['DisplayLabel'], df['Value']))
    source = d.pop('Source')
    test = d.pop('Test')
    result, value = zip(*d.items())

    return pd.DataFrame(
        dict(RecordID=name, Source=source, Test=test, Result=result, Value=value)
    )

pd.concat(map(f, df.groupby('RecordID')))

   RecordID     Source            Test   Result     Value
0         1        Web           Logic  Value 1         S
1         1        Web           Logic  Value 2         I
2         1        Web           Logic  Value 3  Complete
0         2     Person           Voice  Value 1       >20
1         2     Person           Voice  Value 2         P
0         3       Mail             OCR  Value 1         A
1         3       Mail             OCR  Value 2         I
0         4  Dictation  Understandable  Value 1         S
1         4  Dictation  Understandable  Value 2         I
0         5        Web           Logic  Value 1         R
1         5        Web           Logic  Value 2         S

ติดตั้ง

df = pd.DataFrame(data={
    'RecordID': [1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5],
    'DisplayLabel': [
        'Source', 'Test', 'Value 1', 'Value 2', 'Value 3',
        'Source', 'Test', 'Value 1', 'Value 2',
        'Source', 'Test', 'Value 1', 'Value 2',
        'Source', 'Test', 'Value 1', 'Value 2',
        'Source', 'Test', 'Value 1', 'Value 2'
    ],
    'Value': [
        'Web', 'Logic', 'S', 'I', 'Complete',
        'Person', 'Voice', '>20', 'P',
        'Mail', 'OCR', 'A', 'I',
        'Dictation', 'Understandable', 'S', 'I',
        'Web', 'Logic', 'R', 'S'
    ]
})

คุณช่วยอธิบายรายละเอียดขั้นตอนของคุณได้ไหม? ฉันคิดว่าฉันติดตาม แต่สำหรับฉันและคนอื่น ๆ ใน StackOverflow มันอาจมีประโยชน์มาก โดยเฉพาะถ้าคุณมีคอลัมน์มากขึ้นคุณจะแก้ไขมันอย่างไร ขอบคุณมากสำหรับการแก้ปัญหา!
จอน

0

ฉันพยายามใช้วิธีการที่แตกต่างกันครั้งแรกของpivotไอเอ็นจีใช้unstackแล้วบางส่วนแปลงwide_to_long(ขออภัยถ้ามันไม่ได้มีประสิทธิภาพ แต่ดูเหมือนว่าจะได้รับผลลัพธ์ที่ต้องการ)

# first converting all long to wide
df2 = df.set_index(['RecordID','DisplayLabel']).unstack()
# flattening the unstacked columns
df2.columns = df2.columns.to_series().str.join('_')
df2.columns = df2.columns.str.replace('Value_','',regex=True) #just removing the junk in the column name
df2 = df2.reset_index() #resetting index to access RecordID

df2 = (pd.melt(df2,id_vars=['RecordID',"Source","Test"],var_name='Result', value_name='Value')
.sort_values(['RecordID',"Source","Test"])
.dropna()
.reset_index())
index   RecordID    Source  Test    Result  Value
0   0   1   Web Logic   Value 1 S
1   5   1   Web Logic   Value 2 I
2   10  1   Web Logic   Value 3 Complete
3   1   2   Person  Voice   Value 1 >20
4   6   2   Person  Voice   Value 2 P
5   2   3   Mail    OCR Value 1 A
6   7   3   Mail    OCR Value 2 I
7   3   4   Dictation   Understandable  Value 1 S
8   8   4   Dictation   Understandable  Value 2 I
9   4   5   Web Logic   Value 1 R
10  9   5   Web Logic   Value 2 S
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.