ฉันกำลังพยายามรับความถี่ของคำในข้อความทวีตจากไฟล์ csv โดยใช้การนับค่าของแพนด้า

นี่คือรหัสของฉัน:

import nltk
from nltk.corpus import stopwords
from nltk.tokenize import RegexpTokenizer
from nltk.stem import WordNetLemmatizer
import pandas as pd
import numpy as np
import openpyxl
import string

tokenizer = RegexpTokenizer(r'\w+')
lemmatizer = WordNetLemmatizer()


def remove_stopwords(df_text):
    words = [w for w in df_text if w not in stopwords.words('english')]
    return words

def word_lemmatizer(df_text):
    lem_text = [lemmatizer.lemmatize(i) for i in df_text]
    return lem_text

#works fine from here
df = pd.read_csv('amazonfresh-test.csv', encoding='utf-8', converters={'text': str})


df['text'].apply(lambda x: tokenizer.tokenize(x.lower()))
df['text'].apply(lambda x: remove_stopwords(x))
df['text'].apply(lambda x: word_lemmatizer(x))

#to here

#this is where I have issues
data_count = df['test'].apply(pd.value_counts())

data_count.to_excel("amazonfresh-test.xlsx")

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

นี่คือลักษณะของ CSV:

นี่คือ CSV ใหม่ที่มีคำอยู่ในเซลล์ของตัวเอง ซึ่งยังคงประสบปัญหาเพื่อให้ได้ value_count ในเรื่องนี้< /ก>


person Tom    schedule 22.06.2020    source แหล่งที่มา
comment
คุณสามารถให้ตัวอย่าง 'amazonfresh-test.csv' ได้หรือไม่   -  person Phillyclause89    schedule 23.06.2020
comment
ใช่ เพิ่งทำ @ Phillyclause89   -  person Tom    schedule 23.06.2020
comment
ขอบคุณสำหรับภาพหน้าจอ csv คุณได้คอลัมน์ 'test' จากที่ไหนใน data_count = df['test'].apply(pd.value_counts()) ฉันไม่เห็นว่าเป็นคอลัมน์ที่มีอยู่ใน csv ต้นทางของคุณ และฉันไม่เห็นว่าคุณสร้างคอลัมน์ดังกล่าวในโค้ดของคุณก่อนที่คุณจะใช้วิธี pandas.Series.apply   -  person Phillyclause89    schedule 23.06.2020
comment
@ Phillyclause89 ที่ต้องพิมพ์ผิด มันคือการอ้างอิงคอลัมน์ 'ข้อความ' ใน csv   -  person Tom    schedule 23.06.2020
comment
การพิมพ์ผิดนั้นทำให้เกิดปัญหาของคุณหรือพฤติกรรมที่คุณสังเกตเห็นในคำถามนี้เกิดขึ้นโดยไม่มีการพิมพ์ผิดในโค้ดหรือไม่   -  person Phillyclause89    schedule 23.06.2020
comment
@ Phillyclause89 มันเกิดขึ้นโดยไม่มีการพิมพ์ผิด ฉันสามารถแทรกคำย่อ ลบคำหยุด และโทเค็นได้โดยไม่มีปัญหามากเกินไป แต่ฉันมีปัญหาในการพยายามนับมูลค่าของข้อความในคอลัมน์   -  person Tom    schedule 23.06.2020
comment
ฉันไม่คุ้นเคยกับวิธี pandas.value_counts มี pandas.Series.value_counts แต่ฉันไม่แน่ใจว่านี่คือสิ่งที่คุณต้องการใช้ที่นี่หรือไม่ คุณแค่พยายามนับจำนวนโทเค็นที่เหลือหลังจากลบคำหยุดออกแล้วหรือยัง? อาจลอง: data_count = df['text'].apply(lambda x: len(x))?   -  person Phillyclause89    schedule 23.06.2020
comment
@ Phillyclause89 ดูเหมือนว่าโปรแกรมจะใช้เวลานานในการรันอย่างไร้เหตุผล มีเหตุผลอะไรบ้าง?   -  person Tom    schedule 23.06.2020
comment
@ Phillyclause89 ใช่ แค่พยายามนับโทเค็นที่เหลือ สคริปต์ที่คุณแนะนำจะส่งออกเฉพาะตัวเลขเท่านั้น   -  person Tom    schedule 23.06.2020
comment
ฉันคิดว่าฉันเข้าใจสิ่งที่คุณตามหาที่นี่ ฉันใช้เวลาสักครู่ในการติดตั้งแพ็คเกจ nltk ทั้งหมด แต่ตอนนี้ฉันพร้อมและใช้งานสคริปต์ของคุณแล้ว คุณช่วยยืนยันได้ไหมว่าคุณกำลังกด #นี่คือที่ที่ฉันมีปัญหาจริงๆ และบรรทัดด้านล่างมี data_count = df['text'].apply(pd.value_counts()) จริงๆ หรือมีการพิมพ์ผิดอื่นๆ ในบรรทัดนั้นหรือไม่ ตามที่เขียนไว้ฉันได้รับ TypeError: value_counts() missing 1 required positional argument: 'values' เมื่อฉันพยายามเรียกใช้ คุณทราบได้อย่างไรว่าเส้นนี้คือคอขวดของคุณ คุณแน่ใจหรือว่าไม่ใช่หนึ่งในการโทร .apply อื่นๆ   -  person Phillyclause89    schedule 23.06.2020
comment
สองไอเดียหลังจากเล่นกับสิ่งนี้ 1) โปรดทราบว่า pandas.Series.apply ไม่ใช่วิธีการแทนที่ตามค่าเริ่มต้น ฉันคิดว่าคุณต้องการทำ df['text'] = df['text'].apply(func) ในสามบรรทัดนั้นซึ่งดูเหมือนว่าคุณต้องการ tokonize และกรองข้อมูลในคอลัมน์ข้อความ 2) ฉันคิดว่าคุณต้องการลบผู้โทรออกจากฟังก์ชัน pd.value_counts ในบรรทัด data_count = df['test'].apply(pd.value_counts()) ลองทำ data_count = df['test'].apply(pd.value_counts)?   -  person Phillyclause89    schedule 23.06.2020
comment
@ Phillyclause89 โอเคดังนั้นฉันจึงสามารถส่งออก csv โดยแต่ละคำแบ่งออกเป็นเซลล์ของตัวเอง แล้วฉันจะใช้การนับค่าได้อย่างไร ฉันจะแนบ CSV ใหม่ในโพสต์ต้นฉบับ   -  person Tom    schedule 23.06.2020


คำตอบ (1)


หลังจากกลับมาแสดงความคิดเห็นกับ OP เป็นจำนวนมาก ฉันตัดสินใจว่าจะเป็นการดีที่สุดที่จะสรุปข้อเสนอแนะของฉันที่นี่

ปัญหาแรกคือมีการพิมพ์ผิดสองครั้งใน data_count = df['test'].apply(pd.value_counts())

บรรทัดนั้นควรเป็น data_count = df['text'].apply(pd.value_counts) จริงๆ

df['test'] จะเพิ่ม KeyError เนื่องจากไม่มีคอลัมน์ 'test' ใน pandas.DataFrame ของ OP การพิมพ์ผิดอีกประการหนึ่งคือการเรียก pandas.value_counts เข้าสู่ตัวเรียกของเมธอด pandas.Series.apply อย่างไม่มีข้อโต้แย้ง สิ่งนี้จะเพิ่ม TypeError เนื่องจากฟังก์ชัน pandas.value_counts ต้องมีอาร์กิวเมนต์อย่างน้อยหนึ่งตัว แต่สิ่งนี้แก้ไขได้ง่าย ๆ ด้วยการลบผู้เรียกออก เนื่องจากจุดประสงค์ของเมธอด pandas.Series.apply คือการให้มันเรียกใช้ฟังก์ชันให้เราโดยใช้แต่ละค่าในซีรีส์เป็นอาร์กิวเมนต์

ปัญหาถัดไปที่ฉันสังเกตเห็นคือการเรียกอีกสามครั้งของเมธอด pandas.Series.apply:

df['text'].apply(lambda x: tokenizer.tokenize(x.lower()))
df['text'].apply(lambda x: remove_stopwords(x))
df['text'].apply(lambda x: word_lemmatizer(x))

สามบรรทัดนี้เขียนราวกับว่า pandas.Series.apply เป็นวิธีการแบบแทนที่ ซึ่งไม่ใช่ หากต้องการให้การเปลี่ยนแปลง pandas.DataFrame อ็อบเจ็กต์ถูกกำหนดเป็น df จริง ๆ เราจำเป็นต้องใช้การมอบหมายจริงที่นี่:

df['text'] = df['text'].apply(lambda x: tokenizer.tokenize(x.lower()))
df['text'] = df['text'].apply(remove_stopwords)
df['text'] = df['text'].apply(word_lemmatizer)

นอกจากนี้ นิพจน์แลมบ์ดาจำเป็นเฉพาะในการเรียกครั้งแรกเพื่อทำส่วน x.lower() เนื่องจากทั้ง remove_stopwords และ word_lemmatizer รับค่าตามที่เป็นอยู่ เราจึงไม่จำเป็นต้องมีแลมบ์ดาเพิ่มเติม ในที่สุด ทั้งสามบรรทัดสามารถย่อให้เป็นการเรียกเดียวที่ pandas.Series.apply เนื่องจากมีการนำฟังก์ชันเหล่านี้ไปใช้กับค่าเดียวกัน:

df['text'] = df['text'].apply(
    lambda x: word_lemmatizer(
        remove_stopwords(
            tokenizer.tokenize(x.lower())
        )
    )
)

โค้ดเต็มที่ฉันหวังว่า OP จะสามารถรวบรวมจากความคิดเห็นของฉันควรมีลักษณะดังนี้:

from nltk.corpus import stopwords
from nltk.tokenize import RegexpTokenizer
from nltk.stem import WordNetLemmatizer
import pandas as pd

tokenizer = RegexpTokenizer(r'\w+')
lemmatizer = WordNetLemmatizer()


def remove_stopwords(df_text):
    words = [w for w in df_text if w not in stopwords.words('english')]
    return words


def word_lemmatizer(df_text):
    lem_text = [lemmatizer.lemmatize(i) for i in df_text]
    return lem_text


df = pd.read_csv('test.csv', encoding='utf-8', converters={'text': str}, sep="\t")

df['text'] = df['text'].apply(
    lambda x: word_lemmatizer(
        remove_stopwords(
            tokenizer.tokenize(x.lower())
        )
    )
)

data_count = df['text'].apply(pd.value_counts)

data_count.to_excel("test.xlsx")

ไฟล์ Excel ที่สร้างขึ้นนี้ควรมีลักษณะเช่นนี้

ป้อนคำอธิบายรูปภาพที่นี่ หมายเหตุ: ผลลัพธ์ที่แสดงในภาพหน้าจอของฉันมาจากการเรียกใช้โค้ดนี้ใน csv คอลัมน์เดียวที่ประกอบด้วย 100 ประโยคแรกของหนังสือ Dune ฉันไม่ได้ทำ รบกวนสร้าง csv ที่แสดงในภาพหน้าจอของ OP อีกครั้ง เนื่องจากสิ่งเดียวที่ควรสำคัญคือมีคอลัมน์ที่มีคำภาษาอังกฤษจำนวนมากชื่อ 'ข้อความ'

จากเอกสารทั้งหมดนี้ในคำตอบนี้ OP ยังคงมีความคิดเห็นที่ยังไม่ได้ยืนยันหนึ่งรายการ:

@ Phillyclause89 โอเคดังนั้นฉันจึงสามารถส่งออก csv โดยแต่ละคำแบ่งออกเป็นเซลล์ของตัวเอง แล้วฉันจะใช้การนับค่าได้อย่างไร ฉันจะแนบ CSV ใหม่ในโพสต์ต้นฉบับ

คำแนะนำของฉันคือให้มีการใช้ pandas.value_counts ตามที่ฉันได้แสดงในตัวอย่างโค้ดด้านบน (ภายใน pandas.Series.Apply และไม่ต้องเรียกมัน) จากนั้นคุณสามารถใช้วิธี agg ต่างๆ เช่น sum เพื่อค้นหาจำนวนคำในทุกแถว:

agg_data_count = data_count.sum().sort_values(0,ascending=False)
agg_data_count.to_excel("sums.xlsx")

การเปิด sums.xlsx เราจะได้รายการคำศัพท์ที่ดีและจำนวนคำที่ปรากฏในชุดข้อมูลทั้งหมด: ป้อนคำอธิบายรูปภาพที่นี่

person Phillyclause89    schedule 24.06.2020
comment
ยังตระหนักด้วยว่า df['text'].value_counts() ก็ใช้ได้ผลเช่นกัน ขอบคุณสำหรับความช่วยเหลือของคุณ! - person Tom; 24.06.2020