-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
55441ca
commit 1dd709e
Showing
9 changed files
with
476 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { useZustand } from '../lib/useZustand' | ||
import { Select, Button, Form } from 'antd' | ||
import { useState } from 'react' | ||
import { flushSync } from 'react-dom' | ||
import { corr } from 'mathjs' | ||
|
||
type Option = { | ||
/** 变量名 */ | ||
variables: [string, string] | ||
} | ||
type Result = { | ||
r: number | ||
} & Option | ||
|
||
export function CorrReliability() { | ||
|
||
const { dataCols, dataRows, messageApi } = useZustand() | ||
const [result, setResult] = useState<Result | null>(null) | ||
const [disabled, setDisabled] = useState<boolean>(false) | ||
const handleCalculate = (values: Option) => { | ||
const timestamp = Date.now() | ||
try { | ||
messageApi?.loading('正在处理数据...') | ||
const filteredRows = dataRows.filter((row) => values.variables.every((variable) => typeof row[variable] !== 'undefined' && !isNaN(Number(row[variable])))) | ||
const data = values.variables.map((variable) => filteredRows.map((row) => Number(row[variable]))) | ||
const r = corr(data[0], data[1]) | ||
setResult({ | ||
...values, | ||
r: Number(r), | ||
}) | ||
messageApi?.destroy() | ||
messageApi?.success(`数据处理完成, 用时 ${Date.now() - timestamp} 毫秒`) | ||
} catch (error) { | ||
messageApi?.destroy() | ||
messageApi?.error(`数据处理失败: ${error instanceof Error ? error.message : JSON.stringify(error)}`) | ||
} | ||
} | ||
|
||
return ( | ||
<div className='w-full h-full overflow-hidden flex justify-start items-center gap-4 p-4'> | ||
|
||
<div className='w-96 h-full flex flex-col justify-center items-center rounded-md border bg-gray-50 px-4 overflow-auto'> | ||
|
||
<Form<Option> | ||
className='w-full py-4' | ||
layout='vertical' | ||
onFinish={(values) => { | ||
flushSync(() => setDisabled(true)) | ||
handleCalculate(values) | ||
flushSync(() => setDisabled(false)) | ||
}} | ||
autoComplete='off' | ||
disabled={disabled} | ||
> | ||
<Form.Item | ||
label='选择变量(两个)' | ||
name='variables' | ||
rules={[ | ||
{ required: true, message: '请选择变量' }, | ||
{ type: 'array', min: 2, max: 2, message: '请选择两个变量' }, | ||
]} | ||
> | ||
<Select | ||
className='w-full' | ||
placeholder='请选择变量' | ||
mode='multiple' | ||
> | ||
{dataCols.map((col) => col.type === '等距或等比数据' && ( | ||
<Select.Option key={col.name} value={col.name}> | ||
{col.name} | ||
</Select.Option> | ||
))} | ||
</Select> | ||
</Form.Item> | ||
<Form.Item> | ||
<Button | ||
className='w-full mt-4' | ||
type='default' | ||
htmlType='submit' | ||
> | ||
计算 | ||
</Button> | ||
</Form.Item> | ||
</Form> | ||
|
||
</div> | ||
|
||
<div className='w-[calc(100%-24rem)] h-full flex flex-col justify-start items-center gap-4 rounded-md border bg-white overflow-auto p-8'> | ||
|
||
{result ? ( | ||
<div className='w-full h-full overflow-auto'> | ||
|
||
<p className='text-lg mb-2 text-center w-full'>重测信度/复本信度分析</p> | ||
<table className='three-line-table'> | ||
<thead> | ||
<tr> | ||
<td>配对变量A</td> | ||
<td>配对变量B</td> | ||
<td>相关系数(r<sub>xx</sub>)</td> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>{result.variables[0]}</td> | ||
<td>{result.variables[1]}</td> | ||
<td>{result.r.toFixed(3)}</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
|
||
</div> | ||
) : ( | ||
<div className='w-full h-full flex justify-center items-center'> | ||
<span>请填写参数并点击计算</span> | ||
</div> | ||
)} | ||
|
||
</div> | ||
|
||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import { useZustand } from '../lib/useZustand' | ||
import { Select, Button, Form } from 'antd' | ||
import { useState } from 'react' | ||
import { corr } from 'mathjs' | ||
import { flushSync } from 'react-dom' | ||
|
||
type Option = { | ||
/** 前一半变量名 */ | ||
variablesA: string[] | ||
/** 后一半变量名 */ | ||
variablesB: string[] | ||
} | ||
type Result = { | ||
/** 矫正后的相关系数 */ | ||
correctedR: number | ||
} & Option | ||
|
||
export function HalfReliability() { | ||
|
||
const { dataCols, dataRows, messageApi } = useZustand() | ||
const [result, setResult] = useState<Result | null>(null) | ||
const [disabled, setDisabled] = useState<boolean>(false) | ||
const handleCalculate = (values: Option) => { | ||
const timestamp = Date.now() | ||
try { | ||
messageApi?.loading('正在处理数据...') | ||
const filteredRows = dataRows.filter((row) => values.variablesA.concat(values.variablesB).every((variable) => typeof row[variable] !== 'undefined' && !isNaN(Number(row[variable])))) | ||
const meansA = filteredRows.map((row) => values.variablesA.reduce((acc, variable) => acc + Number(row[variable]), 0) / values.variablesA.length) | ||
const meansB = filteredRows.map((row) => values.variablesB.reduce((acc, variable) => acc + Number(row[variable]), 0) / values.variablesB.length) | ||
const r = Number(corr(meansA, meansB)) | ||
const correctedR = 2 * r / (1 + r) | ||
setResult({ | ||
...values, | ||
correctedR, | ||
}) | ||
messageApi?.destroy() | ||
messageApi?.success(`数据处理完成, 用时 ${Date.now() - timestamp} 毫秒`) | ||
} catch (error) { | ||
messageApi?.destroy() | ||
messageApi?.error(`数据处理失败: ${error instanceof Error ? error.message : JSON.stringify(error)}`) | ||
} | ||
} | ||
|
||
return ( | ||
<div className='w-full h-full overflow-hidden flex justify-start items-center gap-4 p-4'> | ||
|
||
<div className='w-96 h-full flex flex-col justify-center items-center rounded-md border bg-gray-50 px-4 overflow-auto'> | ||
|
||
<Form<Option> | ||
className='w-full py-4' | ||
layout='vertical' | ||
onFinish={(values) => { | ||
flushSync(() => setDisabled(true)) | ||
handleCalculate(values) | ||
flushSync(() => setDisabled(false)) | ||
}} | ||
autoComplete='off' | ||
disabled={disabled} | ||
> | ||
<Form.Item | ||
label='选择前一半变量' | ||
name='variablesA' | ||
rules={[ | ||
{ required: true, message: '请选择变量' }, | ||
({ getFieldValue }) => ({ | ||
validator(_, value) { | ||
if (value?.some((variable: string) => getFieldValue('variablesB')?.includes(variable))) { | ||
return Promise.reject('前后两半变量不能重复') | ||
} | ||
return Promise.resolve() | ||
} | ||
}) | ||
]} | ||
> | ||
<Select | ||
className='w-full' | ||
placeholder='请选择变量' | ||
mode='multiple' | ||
> | ||
{dataCols.map((col) => col.type === '等距或等比数据' && ( | ||
<Select.Option key={col.name} value={col.name}> | ||
{col.name} | ||
</Select.Option> | ||
))} | ||
</Select> | ||
</Form.Item> | ||
<Form.Item | ||
label='选择后一半变量' | ||
name='variablesB' | ||
rules={[ | ||
{ required: true, message: '请选择变量' }, | ||
({ getFieldValue }) => ({ | ||
validator(_, value) { | ||
if (value?.some((variable: string) => getFieldValue('variablesA')?.includes(variable))) { | ||
return Promise.reject('前后两半变量不能重复') | ||
} | ||
return Promise.resolve() | ||
} | ||
}) | ||
]} | ||
> | ||
<Select | ||
className='w-full' | ||
placeholder='请选择变量' | ||
mode='multiple' | ||
> | ||
{dataCols.map((col) => col.type === '等距或等比数据' && ( | ||
<Select.Option key={col.name} value={col.name}> | ||
{col.name} | ||
</Select.Option> | ||
))} | ||
</Select> | ||
</Form.Item> | ||
<Form.Item> | ||
<Button | ||
className='w-full mt-4' | ||
type='default' | ||
htmlType='submit' | ||
> | ||
计算 | ||
</Button> | ||
</Form.Item> | ||
</Form> | ||
|
||
</div> | ||
|
||
<div className='w-[calc(100%-24rem)] h-full flex flex-col justify-start items-center gap-4 rounded-md border bg-white overflow-auto p-8'> | ||
|
||
{result ? ( | ||
<div className='w-full h-full overflow-auto'> | ||
|
||
<p className='text-lg mb-2 text-center w-full'>分半信度分析</p> | ||
<table className='three-line-table'> | ||
<thead> | ||
<tr> | ||
<td>前半部分题目数</td> | ||
<td>后半部分题目数</td> | ||
<td>修正后相关系数(r<sub>xx</sub>)</td> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>{result.variablesA.length}</td> | ||
<td>{result.variablesB.length}</td> | ||
<td>{result.correctedR.toFixed(3)}</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
<p className='text-xs mt-3 text-center w-full'>前半部分题目: {result.variablesA.join(', ')}</p> | ||
<p className='text-xs mt-2 text-center w-full'>后半部分题目: {result.variablesB.join(', ')}</p> | ||
|
||
</div> | ||
) : ( | ||
<div className='w-full h-full flex justify-center items-center'> | ||
<span>请填写参数并点击计算</span> | ||
</div> | ||
)} | ||
|
||
</div> | ||
|
||
</div> | ||
) | ||
} |
Oops, something went wrong.